Recursive search and replace in text files on Mac and Linux
Recursive search and replace in text files on Mac and Linux
In the linux shell, the following command will recursively search and replace all instances of 'this' with 'that' (I don't have a Linux shell in front of me, but it should do).
find . -name "*.txt" -print | xargs sed -i 's/this/that/g'
What will a similar command on OSX look like?
apple.stackexchange.com
13 Answers
13
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):
less
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.
-i
-i ''
The following should do:
find . -type f -name '*.txt' -exec sed -i '' s/this/that/ +
find . -type f -name '*.txt' -exec sed -i '' s/this/that/ +
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.)
-type f
-exec
xargs
-print0
+
find
find
Works like a charm, thanks, and welcome to stackoverflow ;-)
– Jack
Mar 15 '12 at 7:33
My "this" in this substitution contains a forward slash (localhost/site) -- I am substituting parts of a URL in an .html file....how do I make such a substitution. I tried putting in double-quotes, but it fails.
– Angela
Sep 18 '13 at 4:00
Sed syntax allows using almost any character in place of the slash, e.g. you could use the
%
character: sed "s%localhost/site%blah/blah%"
. Another alternative is to backslash-escape the separator: sed "s/localhost/site/blah/blah/"
.– TaylanUB
Sep 18 '13 at 11:06
%
sed "s%localhost/site%blah/blah%"
sed "s/localhost/site/blah/blah/"
Anybody else getting
illegal byte sequence
error? if so, try: LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ +
, it worked for me.– CodingCaio
May 31 '16 at 14:10
illegal byte sequence
LC_ALL=C find . -type f -name '*.txt' -exec sed -i '' s/this/that/ +
This will be replacing only one ocurreny per file, use
/g
for multiple ocurrencies like LC_ALL=C find . -type f -exec sed -i '' s/search/replace/g +
– jamesjara
Aug 22 '17 at 6:20
/g
LC_ALL=C find . -type f -exec sed -i '' s/search/replace/g +
For the mac, a more similar approach would be this:
find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"
I wish I could upvote this every time I come back to it and use it. It'd be at +15 by now, easy.
– Droogans
Feb 26 '15 at 15:35
Agreed. This was the only one that worked for me.
– Andrew Faulkner
Aug 11 '16 at 9:00
For some reason, it does not work for me. It does nothing. I'm inside the folder form360 and I´m trying to change all string instances with the name easyform to form360, I´m running the following command:
find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
– Andres Ramos
Jan 26 '17 at 21:23
find . -name '*.php' -print0 | xargs -0 sed -i "" "s/easyform/form360/g"
for me, this should be correct answer. It's the only one that worked for me.
– nosequeldeebee
Feb 1 '17 at 6:08
-print0 | xargs -0 does not work on my mac when file name contains space.
– user2807219
Apr 29 '17 at 10:49
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
On Mac OSX 10.11.5 this works fine:
grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @
xargs -I@ sed -i '' 's/old-word/new-word/g' @ worked for me after trying so many other non working suggestions. Thank you!
– BeC
Dec 28 '16 at 10:57
None of the above work on OSX.
Do the following:
perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt
how to scape '/' if SEARCH_FOR and REPLACE_WITH are paths?
– rraallvv
Mar 29 '13 at 16:35
Use a different delimiter. If you're using paths, a colon or pipe would work. 's|SEARCH|REPLACE|g', for example. Our use braces, as in 'sSEARCHREPLACE'.
– dannysauer
Sep 6 '13 at 1:04
dito question, trying it no on Mac -- but it seems to generate an error? For example, my path gets interpreted as a file? -bash: localhost/nohost: No such file or directory
– Angela
Sep 18 '13 at 4:02
this does not recurse through folders deep. Only one level.
– Sergey Romanov
Nov 27 '13 at 14:05
This works best!
– BadmintonCat
Apr 27 '17 at 7:44
A version that works on both Linux and Mac OS X (by adding the -e
switch to sed
):
-e
sed
export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'
I had to do the export from this answer + the line from the accepted answer (I didn't want backup files to be generated)
– Lance
Apr 29 '14 at 19:46
sed: RE error: illegal byte sequence
– FelikZ
Dec 28 '14 at 15:31
to adress the 'illegal byte sequence' error, try setting the LOCALE before running the command:
export LC_CTYPE=C && export LANG=C
– cjoy
Jan 6 '16 at 1:24
export LC_CTYPE=C && export LANG=C
DO NOT EVER RUN this with '*' instead of '*.filetype' as I did if you are using Git. Or you can say goodbye to all your unpublished work.
– Sergey
May 26 '16 at 9:11
The mac version of the sed command requires an '' after the -i, so this answer is incorrect
– G Huxley
Jul 25 '18 at 22:08
This is my workable one. on mac OS X 10.10.4
grep -e 'this' -rl . | xargs sed -i '' 's/this/that/g'
The above ones use find will change the files that do not contain the search text (add a new line at the file end), which is verbose.
Whenever I type this command I always seem to hose it up, or forget a flag. I created a Gist on github based off of TaylanUB's answer that does a global find replace from the current directory. This is Mac OSX specific.
https://gist.github.com/nateflink/9056302
It's nice because now I just pop open a terminal then copy in:
curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"
You can get some weird byte sequence errors, so here is the full code:
#!/bin/bash
#By Nate Flink
#Invoke on the terminal like this
#curl -s https://gist.github.com/nateflink/9056302/raw/findreplaceosx.sh | bash -s "find-a-url.com" "replace-a-url.com"
if [ -z "$1" ] || [ -z "$2" ]; then
echo "Usage: ./$0 [find string] [replace string]"
exit 1
fi
FIND=$1
REPLACE=$2
#needed for byte sequence error in ascii to utf conversion on OSX
export LC_CTYPE=C;
export LANG=C;
#sed -i "" is needed by the osx version of sed (instead of sed -i)
find . -type f -exec sed -i "" "s|$FIND|$REPLACE|g" +
exit 0
https://bitbucket.org/masonicboom/serp is a go utility (i.e. cross-platform), tested on OSX, that does recursive search-and-replace for text in files within a given directory, and confirms each replacement. It's new, so might be buggy.
Usage looks like:
$ ls test
a d d2 z
$ cat test/z
hi
$ ./serp --root test --search hi --replace bye --pattern "*"
test/z: replace hi with bye? (y/[n]) y
$ cat test/z
bye
If you are using a zsh terminal you're able to use wildcard magic:
sed -i "" "s/search/high-replace/g" *.txt
sed -i "" "s/search/high-replace/g" *.txt
find . -type f | xargs sed -i '' 's/string1/string2/g'
Refer here for more info.
The command on OSX should be exactly the same as it is Unix under the pretty UI.
I thought as much, but nope. It puts a ./ in front of the files when feeding to sed, so sed complains 'invalid command code'. Maybe I'm just tired ;-)
– Jack
Mar 14 '12 at 14:43
@JacobusR, please cut and paste from your OSX terminal -- you must be entering something slightly different.
– glenn jackman
Mar 14 '12 at 15:02
You may want
-print0
added to the find
flags and -0
to the xargs
flags.– jmtd
Mar 14 '12 at 16:46
-print0
find
-0
xargs
You can also just use
-exec sed -i s/this/that/g +
instead of -print
and xargs– Marian
Mar 14 '12 at 16:52
-exec sed -i s/this/that/g +
-print
@JacobusR - this works, even if there's a leading './' pathname. However, if there's an space in the filename, say "./jacobus R.txt", the use of
xargs
might see the space-delimited "./jacobus" as a file to pass to sed
, and then with "R.txt", neither of which exist.– Brett Hale
Mar 14 '12 at 17:02
xargs
sed
could just say $PWD instead of "."
Thank you for your interest in this question.
Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).
Would you like to answer one of these unanswered questions instead?
Should probably moved to
apple.stackexchange.com
as it's not generic enough for linux nor all devs.– AlikElzin-kilaka
Jul 14 '16 at 5:42