Recursive search and replace in text files on Mac and Linux
Solution 1:
OS X uses a mix of BSD and GNU tools, so best always check the documentation (although I had it that less
didn't even conform to the OS X manpage):
https://web.archive.org/web/20170808213955/https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/sed.1.html
sed takes the argument after -i
as the extension for backups. Provide an empty string (-i ''
) for no backups.
The following should do:
find . -type f -name '*.txt' -exec sed -i '' s/this/that/g {} +
The -type f
is just good practice; sed will complain if you give it a directory or so.
-exec
is preferred over xargs
; you needn't bother with -print0
or anything.
The {} +
at the end means that find
will append all results as arguments to one instance of the called command, instead of re-running it for each result. (One exception is when the maximal number of command-line arguments allowed by the OS is breached; in that case find
will run more than one instance.)
If you get an error like "invalid byte sequence," it might help to force the standard locale by adding LC_ALL=C
at the start of the command, like so:
LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/g {} +
Solution 2:
For the mac, a more similar approach would be this:
find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"
Solution 3:
As an alternative solution, I'm using this one on Mac OSX 10.7.5
grep -ilr 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @
Credit goes to: Todd Cesere's answer