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 -Zin the first invocation is a solution to the problem in the second case, too.Using
-rin the secondgrepmakes no sense because you only want to examine precisely the files from the output of the firstgrep.If you just want to list the files, of course, just
grep -lalready does that; presumably, you will want to do something more complex in the secondxargs.An alternative solution might be
The way this works is, if one
-execfails, the file for which it failed will be regarded as a failed predicate byfind, 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 -0etc.In case it's not obvious,
findandgrep -rexamine subdirectories, too. If you just want to examine the current directory, omitting the-rfrom the firstgrepshould work. Forfind, you can add-maxdepth 1before-type fto 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