Come posso eseguire xargs grep sull'output grep che ha spazi?


8

Sto cercando i file in base a un'espressione regolare e quindi sto cercando di cercare tali contenuti. Quindi, per esempio, ho qualcosa del genere

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp" | grep "<name regex>" | xargs grep "<content regex>"

Il problema in cui mi imbatto è che alcuni dei percorsi hanno degli spazi, il che confonde xargs. So che se stavo solo usando find, potrei usare l' -print0argomento (insieme -0all'argomento su xargs) per impedire agli xargs di trattare gli spazi come delimitatori. C'è qualcosa di simile con grep?

O sto affrontando questo problema in modo completamente sbagliato? Ingenuamente, findal grepdi xargs grepsenso per me, ma sono aperto ad altri approcci che producono gli stessi risultati.


2
puoi posizionare gli argomenti xargsusando il -iparametro, a la cat sample.txt | grep "pat t ern" | xargs -i grep "{}"- le parentesi graffe gli dicono dove posizionare l'argomento. Il manuale mi dice che -iè deprecato a favore, -Iquindi forse vale la pena dare un'occhiata anche a quello.
dougBTV

Risposte:


5

Usa qualcosa del genere forse (se gnu grep).

grep -r 'content pattern' --include==*.cpp

uomo grep

--include = GLOB Cerca solo i file il cui nome base corrisponde a GLOB (usando la corrispondenza jolly come descritto in --exclude)

Vedi anche le opzioni per i delimitatori null.

-Z, --null Emette un byte zero (il carattere ASCII NUL) invece del carattere che normalmente segue un nome file. Ad esempio, grep -lZ genera un byte zero dopo ogni nome di file anziché la solita newline. Questa opzione rende l'output inequivocabile, anche in presenza di nomi di file contenenti caratteri insoliti come newline. Questa opzione può essere utilizzata con comandi come find -print0, perl -0, sort -z e xargs -0 per elaborare nomi di file arbitrari, anche quelli che contengono caratteri di nuova riga.

-z, --null-data Tratta l'input come un insieme di righe, ciascuna terminata da un byte zero (il carattere ASCUL NUL) anziché da una nuova riga. Come l'opzione -Z o --null, questa opzione può essere utilizzata con comandi come sort -z per elaborare nomi di file arbitrari.


Si noti che grep -r include='*.cpp'è un glob shell - e quindi è allineato alle caratteristiche w / find . -name '*.cpp' -exec grep -e 'content_pattern' -- {} \;not w /find . -name '*.cpp' | grep 'name_pattern' | xargs grep 'content_pattern'
mikeserv

4

Se devi saltare attraverso molti cerchi, l'efficienza degli xargs viene comunque persa. Ecco un rozzo lavoro in giro:

find . -iname "*.cpp" | grep "<pattern>" | while read -r x; do grep exa "$x"; done

Ogni volta che incontro problemi con spazi nei nomi dei file, la risposta è tra virgolette doppie su una variabile.


Questo esegue il grep interno del loop in modo univoco per ogni linea trovata dal grep esterno. Questo è un sacco di spese generali.
Adam Katz,

3

Utilizzare findper eseguire tutti i filtri del nome file. Piuttosto che

find . -name "*.cpp" | grep "foo" | xargs grep 

fare

find . -name "*.cpp" -name "*foo*" -print0 | xargs -0 grep 

Se vuoi fare qualcosa di leggermente più complicato, ad esempio

find . -name "*.cpp" | egrep "foo|bar" | xargs grep 

tu puoi fare

find . -name "*.cpp" "(" -name "*foo*" -o -name "*bar*" ")" -print0 | xargs -0 grep 

Si noti che questi dovrebbero funzionare anche per i file con newline nei loro nomi.

E, se hai bisogno del potere delle espressioni regolari in piena regola, puoi usare -regex.


2

Questo dovrebbe funzionare anche senza strumenti GNU:

#Find all C++ files that match a certain pattern and then search them
find . -name "*.cpp"  | grep "<name regex>" | perl -pe 's/\n/\0/' \
  | xargs -0 grep "<content regex>"

La perlchiamata sostituisce le interruzioni di riga con caratteri nulli, che consentiranno xargs -0di interpretare l'input su una base per riga anziché su una base per spazio bianco.

Usando GNU, puoi rimuovere la perlchiamata e passare xargs -0 …axargs -d "\n" …

Non hai perlo GNU? Prova awk '{printf "%s%c", $0, 0}'invece.


1
Questo potrebbe non fare la cosa giusta se alcuni dei nomi dei file includono newline (un evento piuttosto insolito, certo, ma non impossibile).
Dhag

@dhag ha un punto valido in merito xargs -d "\n". È un evento molto insolito, ma se non hai il controllo dei dati e sei preoccupato che si tratti di un rischio per la sicurezza, fai attenzione alle aspettative di output.
Adam Katz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.