Sto cercando un modo per cercare file in cui esistono due istanze di parole nello stesso file. Finora ho utilizzato quanto segue per eseguire le mie ricerche:
find . -exec grep -l "FIND ME" {} ;
Il problema che sto riscontrando è che se non c'è esattamente uno spazio tra "TROVA" e "ME", il risultato della ricerca non restituisce il file. Come posso adattare la precedente stringa di ricerca in cui entrambe le parole "TROVA" e "MI esistono in un file invece di "TROVAMI"?
Sto usando AIX.
Risposta accettata:
Con gli strumenti GNU:
find . -type f -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Puoi fare di serie:
find . -type f -exec grep -q FIND {} ; -exec grep -l ME {} ;
Ma ciò comporterebbe fino a due grep
s per file. Per evitare di eseguire così tanti grep
s ed essere ancora portatile pur consentendo qualsiasi carattere nei nomi dei file, potresti 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 }'
}
export LC_ALL=C
find .//. -type f |
convert_to_xargs |
xargs grep -l FIND |
convert_to_xargs |
xargs grep -l ME
L'idea è di convertire l'output di find
in un formato adatto per xargs (che si aspetta uno spazio vuoto (SPC/TAB/NL nel C
locale, YMMV in altre impostazioni locali) elenco separato di parole in cui le virgolette singole, doppie e le barre inverse possono sfuggire agli spazi vuoti e tra loro).
In genere non puoi 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 dei 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
nella directory corrente.
Usando .//.
, perché //
non può apparire altrimenti in un percorso di file come output di find
(perché non esiste una directory con un nome vuoto e /
non è consentito in un nome di file), sappiamo che se vediamo una riga che contiene //
, quindi questa è la prima riga di un nuovo nome file. Quindi possiamo usare quel awk
comando per eseguire l'escape di tutti i caratteri di nuova riga tranne quelli che precedono quelle righe.
Se prendiamo l'esempio sopra, find
verrebbe prodotto nel primo caso (un file):
.//a
./b
Quale awk sfugge a:
.//a
./b
Quindi xargs
lo vede come un argomento. E nel secondo caso (due file):
.//a
.//b
Quale awk
lascerebbe così com'è, quindi xargs
vede due argomenti.
Hai bisogno del LC_ALL=C
quindi sed
, awk
(e alcune implementazioni di xargs
) funzionano per sequenze arbitrarie di byte (anche se non formano caratteri validi nelle impostazioni locali dell'utente), per semplificare lo vuoto definizione ai soli SPC e TAB e per evitare problemi con interpretazioni diverse di caratteri la cui codifica contiene la codifica di backslash da parte delle diverse utilità.