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 grep
essere 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 find
in 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 b
in una directory chiamata a<NL>.
o se sono i due file a
e 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 awk
comando per sfuggire a tutti i caratteri di nuova riga tranne quelli che precedono quelle righe.
Se prendiamo l'esempio sopra, find
output nel primo caso (un file):
.//a
./b
Quale awk sfugge a:
.//a\
./b
Quindi questo lo xargs
vede come un argomento. E nel secondo caso (due file):
.//a
.//b
Che awk
lascerebbe così com'è, quindi xargs
vede due argomenti.