I find all needed files with grep: grep --include=\*.{php,ini,conf,sh} -ril -P "'([\d\w\-\_\.]+)(@domain.com)'" '/var/www_data/somepath/'

Now I assume it's either use of sed or perl to for replacement process, alas I can't figure out how to use above regexp in either of them. I saw this way and this way but as I said, I couldn't get it work with my pattern (and by that I mean that I get > in the next line after executing command. I assume it's problem with regexp shown above when used with sed or perl), so any advice on that matter would be nice.

Also, I don't know if it's possible (it's not really important) but I'd like to print some string for each file in with replacement occurred, for example File fixed: /path/to/file/ (file names taken from grep list maybe?)

  • Can you explain what you are trying to do? (P.S. yes sed and perl can be used to search and replace. Not grep.) – ctrl-alt-delor Sep 6 '14 at 21:12
  • Yeah, I know grep is not for replacements, just for search. I'm just trying to replace all email addresses under certain domain which are listed in double single quotes in huge amount of files. – Igor Yavych Sep 6 '14 at 21:59
  • Also see unix.stackexchange.com/q/32666. It uses grep and xargs to touch only files with a match. – user56041 Nov 11 '16 at 20:03

Typically, when you get a > in the next line after hitting, it means that one of your quotes isn't closed yet. I couldn't find that mistake in your regex. But you do not need to surround the path /var/www_data/somepath/ with single quotes. I assume there are no unusual characters in somepath?

Anyways, I tested your regex with sed. \d\w look like vim syntax for me, that's why I translated it to ascii (which always works). Also, inside of [] you do not need to escape .:

sed -r "s/'([A-Za-z0-9_-.]+)(@domain.com)'/'adsf'/g" test.dat

Indeed you can use sed or perl for your task. You don't necessarily need grep to generate a file list, unless you have GB of data. Then presorting could result in a speed benefit.

To test your regex, you could do the following:

cd /var/www_data/somepath/
sed -r 's|pattern|replace-pattern|g' a_single_file.php

When you're satisfied with the result, just add the -ibak (--in-place=bak) argument and run it on all files

find . -type f -name '*.php' -o -name '*.ini' -o name '*.conf' -o -name '*.sh' \
-exec sed -r -ibak 's|pattern|replace-pattern|g' '{}' \; 

The original files are being put into <orignalname.php>.bak.

To answer your last question. For this job, grep is the tool you want, you could run it on the .bak files generated by sed above:

grep --recursive --include='*.bak' -E --files-with-matches 'pattern' . > files_fixed.txt

or, simply:

find . -type f -name '*.bak'
  • The find piped into sed messes with all the file times, and not just the files where the match occurs. – user56041 Nov 11 '16 at 20:00

With GNU sed you can use sed -i.

sed -i 'script' *.{php,ini,conf,sh}
  • sed messes with all the file times, and not just the files where a match would occur from grep. – user56041 Nov 11 '16 at 20:01

Most Linux:

sed -i 's#FIND#REPLACE#g' *.{php,ini,conf,sh}

On MacOS:

sed -i '' 's#FIND#REPLACE#g' *.{php,ini,conf,sh}

The sed in MacOS is expecting a backup parameter after -i, use empty string if you don't need backup files. The "g" is for global replace, otherwise it's only the first per row.

  • sed messes with all the file times, and not just the files where a match would occur from grep. – user56041 Nov 11 '16 at 20:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.