Con gli strumenti GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Puoi fare in modo standard:
find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
Ma ciò comporterebbe due greps per file. Per evitare di eseguire così tanti se grepessere comunque portatile pur consentendo qualsiasi carattere nei nomi dei file, è possibile fare:
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
L'idea è quella di convertire l'output di findin un formato adatto a xargs (che prevede uno spazio vuoto (SPC / TAB / NL e gli altri spazi vuoti dalle impostazioni locali con alcune implementazioni di xargs) elenco separato di parole in cui è possibile inserire virgolette singole, doppie e barre rovesciate sfuggire agli spazi vuoti e l'un l'altro).
Generalmente non è possibile post-elaborare l'output di find -print, perché separa i nomi dei file con un carattere di nuova riga e non sfugge ai caratteri di nuova riga che si trovano nei nomi di file. Ad esempio se vediamo:
./a
./b
Non abbiamo modo di sapere se si tratta di un file chiamato bin una directory chiamata a<NL>.o se sono i due file ae b.
Usando .//., perché //non può apparire diversamente in un percorso di file come output di find(perché non esiste una directory con un nome vuoto e /non è consentita in un nome di file), sappiamo che se vediamo una riga che contiene //, allora quello è la prima riga di un nuovo nome file. Quindi possiamo usare quel awkcomando per sfuggire a tutti i caratteri di nuova riga tranne quelli che precedono quelle righe.
Se prendiamo l'esempio sopra, findoutput nel primo caso (un file):
.//a
./b
Quale awk sfugge a:
.//a\
./b
Quindi questo lo xargsvede come un argomento. E nel secondo caso (due file):
.//a
.//b
Che awklascerebbe così com'è, quindi xargsvede due argomenti.