Com as ferramentas GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Você pode fazer normalmente:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
Mas isso executaria dois greps por arquivo. Para evitar a execução de muitos se grepainda ser portátil, enquanto permite qualquer caractere nos nomes de arquivo, você pode:
convert_to_xargs() {
sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
{
if (NR > 1) {
printf "%s", line
if (!index($0, "//")) printf "\\"
print ""
}
line = $0
}'
END { print line }'
}
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
A ideia é converter a saída de findpara um formato adequado para xargs (que espera um espaço em branco (SPC / TAB / NL e os outros espaços em branco do seu código do idioma com algumas implementações de xargs)) lista separada de palavras em que aspas simples e duplas e barras invertidas podem espaços em branco de escape e um ao outro).
Geralmente, você não pode pós-processar a saída de find -print, porque ela separa os nomes de arquivo com um caractere de nova linha e não escapa aos caracteres de nova linha encontrados nos nomes de arquivo. Por exemplo, se vemos:
./a
./b
Não temos como saber se é um arquivo chamado bem um diretório chamado a<NL>.ou se são os dois arquivos ae b.
Ao usar .//., porque //não pode aparecer de outra maneira no caminho de um arquivo como resultado de find(porque não existe um diretório com um nome vazio e /não é permitido em um nome de arquivo), sabemos que, se virmos uma linha que contenha //, isso será a primeira linha de um novo nome de arquivo. Portanto, podemos usar esse awkcomando para escapar de todos os caracteres de nova linha, exceto daqueles que precedem essas linhas.
Se pegarmos o exemplo acima, findseria exibido no primeiro caso (um arquivo):
.//a
./b
Qual awk escapa para:
.//a\
./b
Então, isso xargsé visto como um argumento. E no segundo caso (dois arquivos):
.//a
.//b
O awkque sairia como está, então xargsvê dois argumentos.