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 grep
ainda 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 find
para 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 b
em um diretório chamado a<NL>.
ou se são os dois arquivos a
e 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 awk
comando para escapar de todos os caracteres de nova linha, exceto daqueles que precedem essas linhas.
Se pegarmos o exemplo acima, find
seria 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 awk
que sairia como está, então xargs
vê dois argumentos.