6

Why does find . -name "*.xml" | xargs grep FOO returns matchs with filenames, while find . -name "*.xml" | xargs -i -sh -c "grep FOO {}" doesn't?

d9k
  • 1,476
  • 3
  • 15
  • 28
shabunc
  • 23,119
  • 19
  • 77
  • 102

3 Answers3

9

Unless it's a typo in posting your question there shouldn't be a hyphen before sh:

The reason you don't get filenames in the output is that grep is being run with a single file as an argument. To force filename output use -H.

find . -name "*.xml" | xargs -I {} sh -c "grep -H FOO {}"

Also, -i for xargs was deprecated around version 4.2.9. You should use -I {}.

JeffCharter
  • 1,431
  • 17
  • 27
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
5

As a previous answer said, the difference is that grep is being invoked for each file and grep doesn't report the filename if only one file is specified on the command line unless the -H (--with-filename) flag is given.

Why is grep being invoked for each file? That is because (like it or not) the use of the -I (or -i) flag to xargs forces the command to be run once for each argument, like using flag "-L 1" to xargs.

From the manual page:

   -I replace-str
     Replace occurrences of replace-str in the initial-arguments with names read from
     standard input.  Also, unquoted blanks do not terminate input items; instead the
     separator is the newline character.  Implies -x and -L 1.
Mark Polhamus
  • 81
  • 1
  • 2
0

you can just use

find . -name "*.xml" | xargs -I{} grep FOO {}

and you may use -H or -n in grep command as you need.

justin.yqyang
  • 97
  • 1
  • 3