3

Using bash, I try to make a substitutions in files (replace B with C), but only in files which contain a certain string A.

I tried

grep -Rl "A" | xargs sed -i 's/B/C'

But this fails when the filenames contain whitespaces

As an ugly workaround, I came up with the following solution which replaces the whitespaces with a placeholder :

for  FILE in `grep -Rl "A"   | tr " " "@"`; 
  do F1=`echo  $FILE | tr "@" " "`;sed 's/B/C/' "$F1"; 
done

is there a more elegant solution?

Raphael Roth
  • 26,751
  • 15
  • 88
  • 145

3 Answers3

2

You can use --null for grep and -0 for xargs:

grep --null -Rl 'A' . | xargs -0 sed -i '' 's/B/C/'

--null Outputs a zero byte (the ASCII NUL character) after each filename of grep command and xargs -0 reads null terminated input to xargs.

anubhava
  • 761,203
  • 64
  • 569
  • 643
1

You could combine the usage of argument --null for grep, with the argument of -0 for xargs, to have the arguments be separated by NUL characters instead.

man grep:
--null  Prints a zero-byte after the file name.

man xargs:
-0      Change xargs to expect NUL (``\0'') characters as separators,
        instead of spaces and newlines. This is expected to be used in 
        concert with the -print0 function in find(1).
O.O.
  • 828
  • 8
  • 17
1

The UNIX tool to find files is named, appropriately enough, find not grep.

find . -type f -exec grep -l -Z 'A' {} + |
xargs -0 sed -i 's/B/C'
Ed Morton
  • 188,023
  • 17
  • 78
  • 185
  • thanks! Of course I'm aware of find, but your solutions still uses grep (so you use 3 tools instead of 2). I also tried your solution, but I couldn't get it to work because I was missing -Z for grep and -0 for xargs to handle the white-spaces. So, using find instead of grep does not answer my question... – Raphael Roth Aug 26 '16 at 05:05
  • I didn't say not to use grep, I said to use `find` to `find` the files and then `grep` to `g/re/p` inside the files. Yes, 3 tools are better than 2 in this case, the GNU guys went against the UNIX philosophy of each tool doing one thing well when they gave grep the ability to find files (what's next options for `sort`ing output, or how about `paste`ing output from different files?) and now GNU grep is just a mush of confusing unrelated arguments. How can you be missing the GNU grep and xargs options for nul terminated file names when you were using the GNU grep option `-R`? – Ed Morton Aug 26 '16 at 05:14