Di seguito è riportato il testo nel file:

Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Ho bisogno di grep per “42B” e ottieni loutput dal testo sopra come:

Pseudo name=Apple Code=42B state=fault 

Qualcuno ha idea di come ottenere questo risultato utilizzando grep / awk / sed?

Commenti

  • Hai contrassegnato questa domanda solo con " grep ". Allora stai cercando solo soluzioni " grep "? Nella domanda specifichi anche awk & sed. Possiamo aggiungere quei tag? Non ero ' sicuro delle tue intenzioni quando ho modificato la domanda ieri sera.
  • stackoverflow.com/ domande / 12024410 / …

Risposta

Con awk

awk -v RS="" "/42B/" file 

RS= cambia il separatore del record di input da una nuova riga a righe vuote. Se qualsiasi campo in un record contiene /42B/ stampa il record.

"" (la stringa nulla) è una magia valore utilizzato per rappresentare le righe vuote secondo POSIX :

If RS è nullo, i record sono separati da sequenze costituite da un <newline> più uno o più spazi vuoti le righe, le righe vuote iniziali o finali non devono risultare in record vuoti allinizio o alla fine dellinput e un <newline> deve sempre essere un separatore di campo, indipendentemente dal valore di FS è.

I paragrafi di output non saranno essere separato poiché il separatore di output rimane una singola nuova riga. Per assicurarti che ci sia una riga vuota tra i paragrafi di output, imposta il separatore del record di output su due nuove righe:

awk -v RS="" -v ORS="\n\n" "/42B/" file 

Commenti

  • +1 per una soluzione elegante. Tuttavia, ' non è necessario reindirizzare il file …
  • le dita erano sul pilota automatico.
  • @jasonwryan, a meno che non sia necessario accedere al nome del file allinterno di awk (FILENAME), ' non è una cattiva idea usare il reindirizzamento in quanto evita problemi per il nome del file contenente = o che inizia con - (o essendo -), crea messaggi di errore coerenti e evita di eseguire awk o di eseguire altri reindirizzamenti se il file di input non può ' essere aperto.

Risposta

Supponendo che i dati siano strutturati in modo che sia sempre la riga prima e dopo quella che vuoi, puoi usare grep “s -A (after) e -B (before) si scambiano per dirgli di includere 1 riga prima della corrispondenza e 1 riga dopo di essa:

$ grep -A 1 -B 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Se vuoi il file stesso numero di righe prima e dopo il termine di ricerca è possibile utilizzare lopzione -C (contesto):

$ grep -C 1 "42B" sample.txt Pseudo name=Apple Code=42B state=fault 

Se “vuoi essere più rigoroso quando abbini più righe puoi utilizzare lo strumento pcregrep , per trovare una corrispondenza pattern su più righe:

$ pcregrep -M "Pseudo.*\n.*42B.*\nstate.*" sample.txt Pseudo name=Apple Code=42B state=fault 

Il pattern precedente corrisponde come segue:

  • -M – più righe
  • "Pseudo.*\n.*42B.*\nstate.*" – corrisponde a un gruppo di stringhe in cui la prima stringa inizia con la parola "Pseudo" seguito da qualsiasi carattere fino alla fine della riga \n, seguito da qualsiasi carattere fino alla stringa "42B" seguito da qualsiasi carattere fino a unaltra fine della riga (\n), seguita dalla stringa "state" seguita da qualsiasi carattere.

Commenti

  • -C (contesto) può essere utilizzato come scorciatoia, se -A e -B coincidono.
  • @DavidBaggerman – grazie. Aggiunto alla risposta.
  • Perché quello negativo? Questo risponde alla domanda.

Risposta

Il grep di alcune versioni di Unix hanno il flag -p per “paragrafo”. So che AIX lo fa .

grep -p 42B <myfile> 

farebbe esattamente quello che stai chiedendo lì . YMMV e GNU grep non hanno questo flag.

Commenti

  • Avere il flag -p sarebbe meraviglioso. Soprattutto se usato insieme a -v in modo da poter escludere interi paragrafi dalloutput.

Risposta

Probabilmente cè un modo altrettanto semplice per farlo con awk, ma in perl:

cat file | perl -ne "BEGIN { $/="\n\n" }; print if $_ =~ /42B/;" 

Questo in pratica dice di dividere il file in blocchi delimitati da righe vuote, quindi di stampare solo quei blocchi che corrispondono alla tua espressione regolare.

Commenti

  • Questo può essere semplificato utilizzando opzioni e abbreviazioni e perdendo l uso inutile di cat ; perl -00 -ne 'print if /42B/' file

Risposta

Unaltra soluzione perl, senza un riga vuota finale:

perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo 

Esempio

% perl -00ne "if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}" foo Pseudo name=Apple Code=42B state=fault % cat foo Pseudo name=Apple Code=42B state=fault Pseudo name=Prance Code=43B state=good 

Commenti

  • O più brevi (e quindi più leggibili), come ha scritto triplee in un commento: perl -00 -ne 'print if /42B/' file.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *