How to grep and replace

2019-01-06 06:41发布

问题:

I need to recursively search for a specified string within all files and subdirectories within a directory and replace this string with another string.

I know that the command to find it might look like this:

grep 'string_to_find' -r ./*

But how can I replace every instance of string_to_find with another string?

回答1:

Another option is to use find and then pass it through sed.

find /path/to/files -type f -exec sed -i 's/oldstring/new string/g' {} \;


回答2:

I got the answer.

grep -rl matchstring somedir/ | xargs sed -i 's/string1/string2/g'


回答3:

You could even follow like this ..

Example

grep -rl 'windows' ./ | xargs sed -i 's/windows/linux/g'

This will search for the string 'windows' in all files relative to the current directory and replace 'windows' with 'linux' for each occurrence of the string in each file.



回答4:

This works best for me on OS X:

grep -r -l 'searchtext' . | sort | uniq | xargs perl -e "s/matchtext/replacetext/" -pi

Source: http://www.praj.com.au/post/23691181208/grep-replace-text-string-in-files



回答5:

Other solutions mix regex syntaxes. To use perl/PCRE patterns for both search and replace, and avoid processing every file, this works quite well:

grep -rlZP 'match1' | xargs -0r perl -pi -e 's/match2/replace/g;'

where match1 and match2 are usually identical but match1 may be simplified to remove more advanced features that are only relevant to the substitution, e.g. capturing groups.

Translation: grep recursively and list matching files, separated by nul to protect any special characters in the filename, that match this PCRE pattern, then pipe those filenames to xargs which is expecting a null-separated list, but won't do anything if no names are received, and get perl to rewrite each file, substituting lines where matches are found.

Add the I option to grep to ignore binary files, too.



回答6:

Usually not with grep, but rather with sed -i 's/string_to_find/another_string/g' or perl -i.bak -pe 's/string_to_find/another_string/g'.



回答7:

Be very careful when using find and sed in a git repo! If you don't exclude the binary files you can end up with this error:

error: bad index file sha1 signature 
fatal: index file corrupt

To solve this error you need to revert the sed by replacing your new_string with your old_string. This will revert your replaced strings, so you will be back to the beginning of the problem.

The correct way to search for a string and replace it is to skip find and use grep instead in order to ignore the binary files:

sed -ri -e "s/old_string/new_string/g" $(grep -Elr --binary-files=without-match "old_string" "/files_dir")

Credits for @hobs



回答8:

Another option would be to just use perl with globstar.

Enabling shopt -s globstar in your .bashrc (or wherever) allows the ** glob pattern to match all sub-directories and files recursively.

Thus using perl -pXe 's/SEARCH/REPLACE/g' -i ** will recursively replace SEARCH with REPLACE.

The -X flag tells perl to "disable all warnings" - which means that it won't complain about directories.

The globstar also allows you to do things like sed -i 's/SEARCH/REPLACE/g' **/*.ext if you wanted to replace SEARCH with REPLACE in all child files with the extension .ext.



标签: