Linux find files with text and replace

How to search and replace using grep

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:

I don’t believe grep can do this (I could be wrong). Easier ways would be to use sed or perl to do the replacing

@Eddy_Em That will replace the entire line with replace. You need to use grouping to capture the part of the line before and after the substring and then put that in the replacement line. sed -i ‘s/\(.*\)substring\(.*\)/\1replace\2/’

10 Answers 10

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

On OS X 10.10 Terminal, a proper extension string to parameter -i is required. For example, find /path/to/files -type f -exec sed -i «» «s/oldstring/new string/g» <> \; Anyway, providing empty string still creates a backup file unlike described in manual.

Why do I get «sed: RE error: illegal byte sequence». And yes, I added the -i «» for OS X. It works otherwise.

I had the illegal byte sequence issue on macOS 10.12, and this question/answer solved my issue: stackoverflow.com/questions/19242275/….

This touches every file so file times are modified; and converts line endings from CRLF to LF on Windows.

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

This would scan through the matching files twice. once with grep and then again with sed . Using find method is more efficient but this method you mention does work.

On OS X you will need to change sed -i ‘s/str1/str2/g’ to sed -i «» ‘s/str1/str2/g’ for this to work.

@cmevoli with this method, grep goes through all the files and sed only scans the files matched by grep . With the find method in the other answer, find first lists all files, and then sed will scan through all the files in that directory. So this method is not necessarily slower, it depends on how many matches there are and the differences in search speeds between sed , grep and find .

OTOH this way lets you PREVIEW what grep finds BEFORE actually replacing, reducing the risk of failure greatly, especially for regex n00bs like myself

This is also useful when your grep replacement is more clever than sed. For example ripgrep obeys .gitignore while sed doesn’t.

Читайте также:  Astra linux сетевое имя

You could even do it like this:

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.

The grep is only useful if there are files which should not be modified. Running sed on all files will update the file’s modification date but leave the contents unchanged if there are no matches.

@tripleee: Be careful with . but [sed] leave the contents unchanged if there are no matches». When using -i , I believe sed changes the file time of every file it touches, even though the contents are unchanged. sed also converts line endings. I don’t use sed on Windows in a Git repo because all CRLF are changed to LF .

This command needs a «» after the -i to denote that no backup files will be made after the in-place substitution takes place, at least in macosx. Check the man page for details. If you want a backup, this is where you put the extension of the file to be created.

For spaces is file names you need to do NULL termination on grep and xargs. stackoverflow.com/questions/17296525/…

This works best for me on OS X:

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

this is perfect! also works with ag: ag «search» -l -r . | sort | uniq | xargs perl -e ‘s/search/replace’ -pi

Why is the sort -u even part of this? In what circumstances would you expect grep -rl to produce the same file name twice?

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

I think this is probably the easiest method on here to get the job done. Forcing grep when it is not needed is unnecessary.

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.

Читайте также:  Настройка ald клиента astra linux

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 .

Источник

Find and replace text within multiple files

It will not have the graphical interface but I would urge you to examine sed (man sed). It is the stream editor that has been in existence from the start of UNIX.

10 Answers 10

Here I use sed to replace every occurrence of the word «cybernetnews» with «cybernet» in every file with the extension, c, in the directory, /home/user/directory/.

find /home/user/directory -name \*.c -exec sed -i "s/cybernetnews/cybernet/g" <> \; 

A more generic variation where you search recursively from the directory of execution and operate on only regular, readable, writeable files:

find ./ -type f -readable -writable -exec sed -i "s/cybernetnews/cybernet/g" <> \; 

Voted up because sed is the best choice IMO, but answer would be more useful if you explained the components of the answer (personally, I’m not familiar with and curious about the <> \;)

@sequoiamcdowell Woo! I missed this! Sorry. The braces mean basically «for each match» and the escaped semi-colon (\;) is to prevent double parsing. We don’t want the bourne-compatible shell and sed trying to parse the command, just sed.

@Christopher how does it work if the word contains spaces like cyber net news ? How can i convert this to cyber net ?

The stream editor,sed, is a powerful utility for this kind of work and is my first choice, however, if you want to do this from an ordinary text editor using an Ubuntu based native application, I would suggest you take a look at Jedit, It is available in the repositories and can be installed by typing in your console:

sudo apt-get install jedit 

Start jedit, click the search menu item, in the menu list, click the Search in Directory item, you will be presented with the dialog below:

Jedit Search In Folder Dialog

This is similar to that of Notepad++ and does the same thing, I believe this is what you want.

This was perfect for when I was searching for an entire line of code, and was hesitant to escape every single regex-special character if I had done the same thing with sed .

This doesn’t work on a large number of files, after a couple of hours it hadn’t made one replacement, whereas geany took a few minutes to find all the occurrences. This may not be an efficient search and replace but it warmed the room up nicely.

Читайте также:  G код linux cnc

regexxer screenshot

Another GUI option is regexxer:

Even, If you don’t know regex, you can use this tool as a simple string search and replace tool and it will do the job for you, no need for regex or anything.

perl -pi -e 's/oldtext/newtext/g' * 

replaces any occurence of oldtext by newtext in all files in the current folder. However you will have to escape all perl special characters within oldtext and newtext using the backslash.

Check with Geany, it is perfect NPP replacement for Linux. You can do exactly that plus you can use regex.

As far as I can tell, Geany 1.23.1 (packaged with Ubuntu 13.10) allows searching multiple files using regex, but not replacing in them.

You can search and replace in Geany multiple files if you open them all and then using the «in session» button in the Search/Replace dialog.

Ok, The regexxer was pretty much what I had been asking for, I had just skipped it earlier due to its name having regex and I just tend to avoid anything to do with regex. But I was wrong, adn that tool has exactly what is required for search and replace.

A very simple solution: replace in all *.txt files in folder string_1 with string_2 :

sed -i 's/string_1/string_2/g' *.txt 

Great answer! Just some addition. If you want to replace a string in any file of the current directory recursively then try this: sed -i ‘s/string_1/string_2/g’ $(grep -rEl ‘string_1’ ./)

I wrote a little script for just this thing. If you only need the basics and are not familiar with sed etc, take a look here: http://www.csrdu.org/nauman/2010/12/30/bash-script-to-find-and-replace-in-a-set-of-files/

The script is the following:

for f in submit_*; do sed "s/old_db_name/new_db_name/" < $f >a_$f ; mv a_$f $f ; done 

You can use this script, copy code and make a file find_and_replace_in_files.sh .

I have modified it a little; please tell me your opinion.

# ***************************************************************************************** # find_and_replace_in_files.sh # This script does a recursive, case sensitive directory search and replace of files # To make a case insensitive search replace, use the -i switch in the grep call # uses a startdirectory parameter so that you can run it outside of specified directory - else this script will modify itself! # ***************************************************************************************** !/bin/bash # **************** Change Variables Here ************ startdirectory="/your/start/directory" searchterm="test" replaceterm="test=ok!" # ********************************************************** echo "***************************************************" echo "* Search and Replace in Files Version 01-Aug-2012 *" echo "***************************************************" i=0; for file in $(grep -l -R $searchterm $startdirectory) do cp $file $file.bak sed -e "s/$searchterm/$replaceterm/ig" $file > tempfile.tmp mv tempfile.tmp $file let i++; echo "Modified: " $file done echo " *** All Done! *** Modified files:" $i 

Источник

Оцените статью
Adblock
detector