If you want to print only the first level directory, it will be more efficient to exit immediately after finding the first match under this directory. You can achieve this using -q
which returns success for matching otherwise failure and when combined with -r
it exits immediately when a match is found.
for d in */; do grep -qri "hello" -- "$d" && printf "%s\n" "$d"; done
--
is used to indicate the end of options, so whatever follows is file arguments, this protects form any directory named -something
and could be interpreted as an option.
In case you would like the above for
to match directories starting with .
, consider setting shopt -s dotglob
, see also this.
If you need to remove the trailing /
from the output, you can use bash parameter expansion and, instead of "$d"
, print "${d%/}"
.
grep
will scan the folders sequentially (you cannot get a result from tmp1, then another from tmp2, then back one from tmp1) so it would be better to useuniq
instead ofsort -u
, as it won't need to keep everything in memory, and it will produce the results as they are printed – Ángel Dec 03 '20 at 00:51grep
searches in directory order I wanted to be sure the output could be the expectedtmp1
,tmp2
rather thantmp2
,tmp1
. It would be possible to replace theawk
withuniq
, or thesed
withcut -d/ -f1
, as there are often multiple routes to a solution – Chris Davies Dec 03 '20 at 07:52