Recursive search and replace in text files on Mac

2019-01-12 15:30发布

问题:

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?

回答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://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/ {} +

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.)



回答2:

For the mac, a more similar approach would be this:

find . -name '*.txt' -print0 | xargs -0 sed -i "" "s/form/forms/g"


回答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



回答4:

On Mac OSX 10.11.5 this works fine:

grep -rli 'old-word' * | xargs -I@ sed -i '' 's/old-word/new-word/g' @


回答5:

None of the above work on OSX.

Do the following:

perl -pi -w -e 's/SEARCH_FOR/REPLACE_WITH/g;' *.txt


回答6:

A version that works on both Linux and Mac OS X (by adding the -e switch to sed):

export LC_CTYPE=C LANG=C
find . -name '*.txt' -print0 | xargs -0 sed -i -e 's/this/that/g'


回答7:

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.



回答8:

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


回答9:

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


回答10:

If you are using a zsh terminal you're able to use wildcard magic:

sed -i "" "s/search/high-replace/g" *.txt



回答11:

find . -type f | xargs sed -i '' 's/string1/string2/g'

Refer here for more info.



回答12:

The command on OSX should be exactly the same as it is Unix under the pretty UI.



回答13:

could just say $PWD instead of "."