I'm looking for all the files in a directory that contain "AAA" and "BBB". I then want to modify/do stuff with each of the found files. The file names do contain spaces.
grep
piping to grep
would seem simple but requires the xargs
to function correctly.
The multiple match functionality in grep
(from what I can tell) is only for "AAA" or "BBB".
What I've got is:
for FILENAME in "$(grep -ilrZ "AAA" ./files/* | xargs -0 grep -ilr "BBB")"
do
echo "$FILENAME"
echo "match"
done
However, this treats the list as files (including the newlines) as a single entity (i.e. "match" will only print once).
Removing the double quotes from the for
sub-shell means every space is a new thing to be looped over, which breaks up filenames.
Your use of grep -Z
in the first invocation is a solution to the problem in the second case, too.
grep -ilrZ "AAA" ./files/* |
xargs -r0 grep -Zil "BBB" |
xargs -r0 -i echo "{} match"
Using -r
in the second grep
makes no sense because you only want to examine precisely the files from the output of the first grep
.
If you just want to list the files, of course, just grep -l
already does that; presumably, you will want to do something more complex in the second xargs
.
An alternative solution might be
find ./files -type f \
-exec grep -qi "AAA" {} \; \
-exec grep -qi "BBB" {} \; \
-exec sh -c 'for f; do echo "$f matched"; done' _ {} +
The way this works is, if one -exec
fails, the file for which it failed will be regarded as a failed predicate by find
, and so the remainder of the predicates will be skipped. The files which reach the final predicate will have returned success from all the previous predicates.
The latter should work on non-Linux platforms which lack the GNU extensions grep -Z
, xargs -0
etc.
In case it's not obvious, find
and grep -r
examine subdirectories, too. If you just want to examine the current directory, omitting the -r
from the first grep
should work. For find
, you can add -maxdepth 1
before -type f
to only examine the current directory.
Demo: https://ideone.com/ELqKxZ
For much more on this topic, see also https://mywiki.wooledge.org/BashFAQ/020 and perhaps https://mywiki.wooledge.org/DontReadLinesWithFor