1

How can I execute this search and replace on Linux without getting an error?

$ git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

$ find . -not -path './.git' -type f -exec sed -i -e 's/old/new/g' -e 's/old2/new2/g' {} +
$ git status
fatal: unknown index entry format 0x74650000

The strings old and new are placeholders.

1
  • 1
    The sed as shown looks very suspicious (unless the old and new are placeholders). If you actually globally replace all old by new, then every old2 will already have changed to new2. And all bold, gold and folder will be bnew, gnew and fnewer. I suspect you have munged something important within git. Jan 3 at 18:01

1 Answer 1

0

The -path test of find matches the entire name. From man find (emphasis mine):

-path pattern

File name matches shell pattern pattern. The metacharacters do not treat /' or .' specially; so, for example,

    find . -path "./sr*sc"

will print an entry for a directory called ./src/misc (if one exists). To ignore a whole directory tree, use -prune rather than checking every file in the tree. Note that the pattern match test applies to the whole file name, starting from one of the start points named on the command line. It would only make sense to use an absolute path name here if the relevant start point is also an absolute path. This means that this command will never match anything:

 find bar -path /foo/bar/myfile -print

Find compares the -path argument with the concatenation of a directory name and the base name of the file it's examining. Since the concatenation will never end with a slash, -path ar‐ guments ending in a slash will match nothing (except perhaps a start point specified on the command line). The predicate -path is also supported by HP-UX find and is part of the POSIX 2008 standard.

So your -not -path './.git' isn't actually excluding anything. For example, on one of my repositories:

$ find . -not -path './.git' -type f | grep -m5 git 
./.git/COMMIT_EDITMSG
./.git/logs/HEAD
./.git/logs/refs/heads/master
./.git/description
./.git/HEAD

You wanted to use something like this, which excludes files starting with ./git/ and followed by any (or no) character(s):

find . -not -path './.git/*' -type f

But even that isn't what you really want. You want to just skip the entire ./.git sub-directory and that's what -prune is for as mentioned in the man page I quoted above:

find . -type f \( -path './.git/*' -o -print \)

You must log in to answer this question.