0

How can I replace all instances of ABC with XYZ in the current directory and all subdirectories?

In this popular question the top answers note that it's unwise to run commands like

find /home/www -type f -print0 | xargs -0 sed -i 's/subdomainA\.example\.com/subdomainB.example.com/g'

in a folder containing .git directory, because the history can become corrupted.

How therefore can I do a replace in a folder that does have a .git directory in it? How's this?:

find /home/www/ -type f -not -path .git/ -exec \
    sed -i 's/ABC/XYZ/g' {} +
Hatshepsut
  • 5,962
  • 8
  • 44
  • 80

2 Answers2

3

You need to "prune" the .git directory. Find's -prune directive always succeeds and, as a side effect, terminates search within the directory; and find's or operator is short-circuit, so:

find $top -name .git -prune -o -type f -print0 | xargs -0 ...

for instance. This says: for each file, if the name is .git and -prune succeeds, we're done (and -prune did succeed and we don't descend into .git). Otherwise, the name was not .git, so we do the "or" clause: if the type is "file", -print0.

Hence, this prints all the names of files that are not a .git directory, nor within a .git directory. (Of course a .git directory is already also not a file, but we had to test for that to use -prune.)

torek
  • 448,244
  • 59
  • 642
  • 775
1

In this popular question the top answers note that it's unwise to run commands like find /home/www -type f -print0 | xargs -0 sed -i 's/ABC/ABX/g' in a folder containing .git directory, because the history can become corrupted.

It's not just git directories, it's anything being used for software development. Build products, databases, expected results from tests ... a command like that is begging for trouble.

git grep -lIz ABC | xargs -0 sed -i 's/ABC/DEF/g'

will get you just tracked text files, that's a decent start, and you can supply pathname patterns as well (e.g. git grep foobar -- '*.[ch]' shows all matching lines in tracked .c and .h files)

jthill
  • 55,082
  • 5
  • 77
  • 137