I want to recursively find files in my source tree by contents. I've tried the following using grep:

$ grep -rn printf | grep %s | grep bcm_errmsg\(rv\)

This returns me every line as I wanted but now, I would like to get the filename of each file that matches, so I changed it to:

$ grep -rn printf | grep %s | grep -l bcm_errmsg\(rv\)

but instead of printing the filenames, I only get

(standard input)

printed to stdout. How do I fix this to get each filename & path (to use sed on it)?

What I want to do: Find every file with printf lines that also contain %s and bcm_errmsg(rv) and then apply the following sed command to the files found:

sed -i 's/%s/%d/g; s/bcm_errmsg(rv)/rv/g;'
  • Assuming that the order of printf, %s and bcm_errmsg(rv) is unambiguous, you should be able to construct a single regular expression that matches all three in a single grep. In fact if you end goal is to edit the matching files in sed, I doubt you need grep at all - just let sed do the pattern matching – steeldriver Jul 6 '17 at 13:30
  • For my GNU grep 2.27, the filename is automatically prefixed with option -r. Later grepping behind the pipe doesn't remove that path, so your sed knows everything before the first : is the path. – Philippos Jul 6 '17 at 13:46
  • @steeldriver please see EDIT1 above – cerr Jul 6 '17 at 13:54
  • Do you want to apply the sed commands to every line in files that contain the matching text, or only to the matching lines themselves? – steeldriver Jul 6 '17 at 14:17
  • 4
    Possible duplicate of multiple replacements on single line with sed – Gohu Jul 6 '17 at 21:11

Following @steeldriver's initial idea, you can do:

egrep -rl '.*printf.*%s.*bcm_errmsg\(rv\).*' . | xargs -d '\n' sed -i '/printf/ s/%s/%d/; /printf/ s/bcm_errmsg(rv)/rv/'
  • This almost works only that if there's a printf with a %s sign, it will replace it with %d even if it does not contain bcm_errmsg(rv) which is wrong... – cerr Jul 6 '17 at 20:24
  • @cerr. Answer updated. – Gohu Jul 6 '17 at 20:53
  • This selects those files that have a printf, then a %s, and bc_errmsg(v) in that order. It will completely miss out on those files that happen to have these 3 strings in some other order. – user218374 Jul 8 '17 at 7:25
  • Even the sed command is incorrect in that it does the s/// only on the lines that contain printf. Per OP the subs need to happen only on those lines that contain all 3 strings. – user218374 Jul 8 '17 at 7:27
grep -rlZP '(?=.*printf)(?=.*%s)(?=.*bcm_errstr\(rv\))' . |
xargs -r0 sed -i -e '

We first run a recursive dir. from the current dir that scans for files which have the strings: printf, %s, and bcm_errstr(rv) on the same line but maybe in any order. The grep options that help us do that are:

  • -r => will recursively launch on all files in the current dir and below.
  • -l => will list filenames that match the criteria, viz., all 3 strings on same line.
  • -Z => the selected filenames are null separated (\0) rather than the usual newline (\n) so that we are able to tackle any kind of filenames.
  • -P => enable the Perl regex engine whereby we are able to use lookaheads to determine whether the 3 strings are existing on the same line.

On the other side of the pipe, xargs is waiting to receive the filenames, separated by \0. It then feeds all these filenames, as much as possible, to sed command line. The sed command you already know from your previous question , where it performs the subs. only on those lines that contain the 3strings on the same line.


I think you're overcomplicating things. To look for string foo in all files located in the current dir and subdirs, simply run

grep -r "foo" *

By default, grep outputs the matching line prepended by the filename where it was found.

The following will instead only output the filename, without the matching line:

grep -rl "foo" *
  • ... so the latter can't do the additional filter steps that are required in the question – Philippos Jul 6 '17 at 13:49
  • @steeldriver please see EDIT1 above – cerr Jul 6 '17 at 13:54

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.