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 eseguireawk
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
.