Command Line: Search and Replace in All Filenames Matched by Grep

Command line: search and replace in all filenames matched by grep

Do you mean search and replace a string in all files matched by grep?

perl -p -i -e 's/oldstring/newstring/g' `grep -ril searchpattern *`

Edit

Since this seems to be a fairly popular question thought I'd update.

Nowadays I mostly use ack-grep as it's more user-friendly. So the above command would be:

perl -p -i -e 's/old/new/g' `ack -l searchpattern`

To handle whitespace in file names you can run:

ack --print0 -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

you can do more with ack-grep. Say you want to restrict the search to HTML files only:

ack --print0 --html -l searchpattern | xargs -0 perl -p -i -e 's/old/new/g'

And if white space is not an issue it's even shorter:

perl -p -i -e 's/old/new/g' `ack -l --html searchpattern`
perl -p -i -e 's/old/new/g' `ack -f --html` # will match all html files

Find and Replace string in all files recursive using grep and sed

As @Didier said, you can change your delimiter to something other than /:

grep -rl $oldstring /path/to/folder | xargs sed -i s@$oldstring@$newstring@g

How to replace a string in multiple files in linux command line


cd /path/to/your/folder
sed -i 's/foo/bar/g' *

Occurrences of "foo" will be replaced with "bar".

On BSD systems like macOS, you need to provide a backup extension like -i '.bak' or else "risk corruption or partial content" per the manpage.

cd /path/to/your/folder
sed -i '.bak' 's/foo/bar/g' *

How can I grep/sed taking find/replace pairs from a file?

You can make a file with a list of sed commands like this in a file called commands.sed:

s|cat|cats|g
s|dog|dogs|g
s|person|people|g

and run it on some input with:

echo "House mouse cat dog person dog person" | sed -f commands.sed

and it will replace cat with cats, dog with dogs and person with people producing:

House mouse cats dogs people dogs people

So we want to turn your file with substitutions into a command file like that - using sed! So, if your replacements file subs.txt contains lines like this with the two words on each line separated by a TAB:

cat cats
dog dogs
person people

That would be:

sed -e 's/^/s|/' -e $'s/\t/|/' -e 's/$/|g/' subs.txt > commands.sed

and then you can apply it with:

sed -f commands.sed SomeFile

Rather than creating a file with the commands in, we can run a process substitution like this to dynamically generate them, and do it all in one go with:

echo "House mouse cat dog person dog person" | sed -f <(sed -e 's/^/s|/' -e $'s/\t/|/' -e 's/$/|g/' subs.txt)

Find and replace filename recursively in a directory

You can do it this way:

find . -name '123_*.txt' -type f -exec sh -c '
for f; do
mv "$f" "${f%/*}/${f##*/123_}"
done' sh {} +

No pipes, no reads, no chance of breaking on malformed filenames, no non-standard tools or features.

Best way to do a find/replace in several files?


find . -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

The first part of that is a find command to find the files you want to change. You may need to modify that appropriately. The xargs command takes every file the find found and applies the sed command to it. The sed command takes every instance of from and replaces it with to. That's a standard regular expression, so modify it as you need.

If you are using svn beware. Your .svn-directories will be search and replaced as well. You have to exclude those, e.g., like this:

find . ! -regex ".*[/]\.svn[/]?.*" -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

or

find . -name .svn -prune -o -type f -print0 | xargs -0 -n 1 sed -i -e 's/from/to/g'

How to find all files containing specific text (string) on Linux

Do the following:

grep -rnw '/path/to/somewhere/' -e 'pattern'
  • -r or -R is recursive,
  • -n is line number, and
  • -w stands for match the whole word.
  • -l (lower-case L) can be added to just give the file name of matching files.
  • -e is the pattern used during the search

Along with these, --exclude, --include, --exclude-dir flags could be used for efficient searching:

  • This will only search through those files which have .c or .h extensions:
grep --include=\*.{c,h} -rnw '/path/to/somewhere/' -e "pattern"
  • This will exclude searching all the files ending with .o extension:
grep --exclude=\*.o -rnw '/path/to/somewhere/' -e "pattern"
  • For directories it's possible to exclude one or more directories using the --exclude-dir parameter. For example, this will exclude the dirs dir1/, dir2/ and all of them matching *.dst/:
grep --exclude-dir={dir1,dir2,*.dst} -rnw '/path/to/somewhere/' -e "pattern"

This works very well for me, to achieve almost the same purpose like yours.

For more options, see man grep.

Using grep and sed to find and replace a string

You can use find and -exec directly into sed rather than first locating oldstr with grep. It's maybe a bit less efficient, but that might not be important. This way, the sed replacement is executed over all files listed by find, but if oldstr isn't there it obviously won't operate on it.

find /path -type f -exec sed -i 's/oldstr/newstr/g' {} \;

Ensuring grep matches from multiple files are on their own line

How about (using your method of parsing):

STRING=$(
for FILE in "${FILENAMES[@]}"; do
grep "find a line with data1 and data2" "$FILE" | sed -rn "s/(data1).*(data2).*/\1/p"
done
)

or if there are not too many files:

STRING=$(grep -h "find a line with data1 and data2" "${FILENAMES[@]}" | sed -rn "s/(data1).*(data2).*/\1/p")

==> Given your script, I am assuming <---- File1 and such is no part of the output format..



Related Topics



Leave a reply



Submit