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%/}".
grepwill 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 useuniqinstead 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:51grepsearches in directory order I wanted to be sure the output could be the expectedtmp1,tmp2rather thantmp2,tmp1. It would be possible to replace theawkwithuniq, or thesedwithcut -d/ -f1, as there are often multiple routes to a solution – Chris Davies Dec 03 '20 at 07:52