usando xargs per grep più pattern


12

Ho un file che ha termini per i quali voglio grep, ogni termine è una riga nel file. Pensavo di poterlo fare con xargs. Quello che sono in grado di trarre da esempi dalla pagina man in questo modo

find ./work -print0 | xargs -0 rm

è che xargs aggiunge l'output del comando pre-pipe alla fine dei suoi argomenti. Quindi, se la ricerca fosse tornata report.doc, allora xargs avrebbe costruito rm report.doc. Questa comprensione è corretta?

Quindi poiché voglio che i valori nel mio file siano al centro del comando grep, devo specificare un segnaposto. Giocando, ci ho provato {}, ma non ha funzionato:

$> cat strings.txt | xargs grep {} subdirectory/*
grep: string1: No such file or directory
grep: string2: No such file or directory

Xargs è lo strumento giusto? In tal caso, qual è la sintassi?

Risposte:


17

Sì, find ./work -print0 | xargs -0 rmeseguirà qualcosa di simile rm ./work/a "work/b c" .... Puoi controllare con echo, find ./work -print0 | xargs -0 echo rmstamperà il comando che sarà eseguito (tranne che lo spazio bianco sarà evaso in modo appropriato, anche se echonon lo mostrerà).

Per arrivare xargsa mettere i nomi nel mezzo, è necessario aggiungere -I[string], dove si [string]trova ciò che si desidera sostituire con l'argomento, in questo caso si utilizzerà -I{}, ad es <strings.txt xargs -I{} grep {} directory/*.

Quello che vuoi effettivamente usare è grep -F -f strings.txt:

-F, --fixed-strings
  Interpret PATTERN as a  list  of  fixed  strings,  separated  by
  newlines,  any  of  which is to be matched.  (-F is specified by
  POSIX.)
-f FILE, --file=FILE
  Obtain  patterns  from  FILE,  one  per  line.   The  empty file
  contains zero patterns, and therefore matches nothing.   (-f  is
  specified by POSIX.)

Quindi grep -Ff strings.txt subdirectory/*troverai tutte le occorrenze di qualsiasi stringa strings.txtcome letterale, se lasci cadere l' -Fopzione puoi usare espressioni regolari nel file. In realtà potresti grep -F "$(<strings.txt)" directory/*anche usare . Se vuoi esercitarti find, puoi utilizzare gli ultimi due esempi nel riepilogo. Se si desidera eseguire una ricerca ricorsiva anziché solo il primo livello, sono disponibili alcune opzioni, anche nel riepilogo.

Sommario:

# grep for each string individually.
<strings.txt xargs -I{} grep {} directory/*

# grep once for everything
grep -Ff strings.txt subdirectory/*
grep -F "$(<strings.txt)" directory/*

# Same, using file
find subdirectory -maxdepth 1 -type f -exec grep -Ff strings.txt {} +
find subdirectory -maxdepth 1 -type f -print0 | xargs -0 grep -Ff strings.txt

# Recursively
grep -rFf strings.txt subdirectory
find subdirectory -type f -exec grep -Ff strings.txt {} +
find subdirectory -type f -print0 | xargs -0 grep -Ff strings.txt

Potresti voler utilizzare l' -lopzione per ottenere solo il nome di ciascun file corrispondente se non hai bisogno di vedere la riga effettiva:

-l, --files-with-matches
  Suppress  normal  output;  instead  print the name of each input
  file from which output would normally have  been  printed.   The
  scanning  will  stop  on  the  first match.  (-l is specified by
  POSIX.)

4

xargspotrebbe non essere lo strumento migliore che suggerirei fgrepse il tuo file di stringhe da abbinare contiene solo stringhe, non espressioni regolari.

fgrep -f strings.txt subdirectory/*

Suggerisco fgrepcome Unix tradizionale grepe egrepnon avevo l'opzione "-f". Credo che GNU grepe egrepabbia l'opzione "-f", quindi se il tuo file contiene espressioni regolari, vorresti usare una versione GNU.

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.