17

I have some files that contain a particular strings. What I want to do is, search a location for the file; if the file exists grep for the pattern; if true, do something.

find -iname file.xxx| xargs -I {} if grep -Fq "string" {} ; then echo {} ; fi

The problems are:

  • xargs is not working with the if statement.
  • echo {} does not give the file name, instead gives {}.

How do I fix these?

jcollado
  • 39,419
  • 8
  • 102
  • 133
Population Xplosive
  • 581
  • 2
  • 8
  • 18

3 Answers3

32

Try to run the command through a shell like this:

$ find -iname file.xxx |
> xargs -I {} bash -c 'if grep -Fq "string" {} ; then echo {} ; fi'

where the original command has been surrounded by quotes and bash -c.

jcollado
  • 39,419
  • 8
  • 102
  • 133
  • 1
    `find` + `xargs` for parallel. But if you try to do some complex thing inside `xargs`, it becomes real ugly. :/ – user2959760 Jun 09 '23 at 14:11
10

Wrap the if-statement in a call to sh:

find -iname file.xxx | xargs -I {} sh -c 'grep -Fq "string" {} && { echo {}; }'

Use a while-loop instead of xargs

find -iname file.xxx | while read -r file; do
  if grep -Fq "$file"; then
    # do something
    echo "$file"
  fi
done

I assume you want to do more than echo the filename. If that's all you're trying to do, use grep's -l option:

find -iname file.xxx | xargs grep -Fl "string"
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
2

First, if is a bash-command and no executable program. xargs on the other hand needs a distinct program.

Second, the ; characters are probably splitting the your command. You would have to escape them in order to get them throu to xargs.

To avoid all this I suggest the following:

for i in `find -iname file.xxx` ; do grep -Fq "string" $i && echo $i ; done
Quota
  • 573
  • 3
  • 11
  • 3
    In general, using a for-loop is not recommended due to the way it word-splits the output of find -- filenames with spaces will be split. Better to use a while-loop to read the filenames. – glenn jackman Feb 28 '12 at 15:25