How to grep and replace

LinuxGrepReplace

Linux Problem Overview


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?

Linux Solutions


Solution 1 - Linux

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' {} \;

Solution 2 - Linux

I got the answer.

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

Solution 3 - Linux

You could even do it 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.

Solution 4 - Linux

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

Solution 5 - Linux

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

Solution 6 - Linux

Other solutions mix regex syntaxes. To use perl/PCRE patterns for both search and replace, and process only matching files, this works quite well:

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

match1 and match2 are usually identical but match2 can contain more advanced features that are only relevant to the substitution, e.g. capturing groups.

Translation: grep recursively and list matching filenames, each separated by null to protect any special characters; pipe any filenames to xargs which is expecting a null-separated list; if any filenames are received, pass them to perl to perform the actual substitutions.

For case-sensitive matching, drop the i flag from grep and the i pattern modifier from the s/// expression, but not the i flag from perl itself. To include binary files, remove the I flag from grep.

Solution 7 - Linux

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

Solution 8 - Linux

Here is what I would do:

find /path/to/dir -type f -iname "*filename*" -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

this will look for all files containing filename in the file's name under the /path/to/dir, than for every file found, search for the line with searchstring and replace old with new.

Though if you want to omit looking for a specific file with a filename string in the file's name, than simply do:

find /path/to/dir -type f -print0 | xargs -0 sed -i '/searchstring/s/old/new/g'

This will do the same thing above, but to all files found under /path/to/dir.

Solution 9 - Linux

Modern rust tools can be used to do this job. For example to replace in all (non ignored) files "oldstring" and "oldString" with "newstring" and "newString" respectively you can :

Use fd and sd

fd -tf -x sd 'old([Ss]tring)' 'new$1' {}

Use ned

ned -R -p 'old([Ss]tring)' -r 'new$1' .

Use ruplacer

ruplacer --go 'old([Ss]tring)' 'new$1' .

Ignored files

To include ignored (by .gitignore) and hidden files you have to specify it :

  • use -IH for fd,
  • use --ignored --hiddenfor ruplacer.

Solution 10 - Linux

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbilltianView Question on Stackoverflow
Solution 1 - LinuxrezizterView Answer on Stackoverflow
Solution 2 - LinuxbilltianView Answer on Stackoverflow
Solution 3 - LinuxDulacosteView Answer on Stackoverflow
Solution 4 - LinuxMarc JuchliView Answer on Stackoverflow
Solution 5 - LinuxminopretView Answer on Stackoverflow
Solution 6 - LinuxWalfView Answer on Stackoverflow
Solution 7 - Linuxtsveti_ikoView Answer on Stackoverflow
Solution 8 - LinuxtinnickView Answer on Stackoverflow
Solution 9 - LinuxKpymView Answer on Stackoverflow
Solution 10 - LinuxGuiltyDolphinView Answer on Stackoverflow