Mai jos este textul din fișier:

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

Trebuie să grep pentru „42B” și obțineți rezultatul din textul de mai sus, cum ar fi:

Pseudo name=Apple Code=42B state=fault 

Are cineva idee despre cum să realizăm acest lucru folosind grep / awk / sed?

Comentarii

  • Ați etichetat această întrebare doar cu " grep ". Căutați doar soluții " grep " atunci? În întrebare specificați și awk & sed. Putem adăuga aceste etichete? Nu eram ' sigur de intenția ta când am editat întrebarea aseară.
  • stackoverflow.com/ questions / 12024410 / …

Răspuns

Cu awk

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

RS= modifică separatorul de înregistrări de intrare de la o linie nouă la linii goale. Dacă vreun câmp dintr-o înregistrare conține /42B/ tipăriți înregistrarea.

"" (șirul nul) este o magie valoare utilizată pentru a reprezenta liniile goale conform POSIX :

Dacă RS este nul, apoi înregistrările sunt separate prin secvențe formate dintr-un <newline> plus unul sau mai multe goluri liniile, liniile goale care conduc sau nu sunt rezultate în înregistrări goale la începutul sau la sfârșitul intrării și un <newline> trebuie să fie întotdeauna un separator de câmp, indiferent de valoarea FS este.

Paragrafele de ieșire nu vor să fie separate deoarece separatorul de ieșire rămâne o singură linie nouă. Pentru a vă asigura că există o linie goală între paragrafele de ieșire, setați separatorul de înregistrări de ieșire la două linii noi:

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

Comentarii

  • +1 pentru o soluție elegantă. ' nu trebuie să redirecționați fișierul deși …
  • degetele erau pe pilot automat.
  • @jasonwryan, cu excepția cazului în care aveți nevoie de acces la numele fișierului din awk (FILENAME), ' nu este o idee rea să folosiți redirecționarea, deoarece evită probleme pentru numele fișierului care conține = sau începând cu - (sau fiind -), face ca mesajele de eroare să fie consistente și evită rularea awk sau efectuarea altor redirecționări dacă fișierul de intrare nu poate fi ' deschis.

Răspuns

Presupunând că datele sunt structurate astfel încât să fie întotdeauna linia înainte și după aceea pe care o doriți, puteți folosi grep „s -A (după) și -B (înainte) comută pentru a-i spune să includă 1 linie înainte de meci și 1 linie după aceasta:

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

Dacă doriți ca același număr de linii înainte și după termenul de căutare puteți utiliza comutatorul -C (context):

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

Dacă „doriți să fiți mai stricți atunci când potriviți mai multe linii, puteți utiliza instrumentul pcregrep , pentru a se potrivi model peste mai multe linii:

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

Modelul de mai sus se potrivește după cum urmează:

  • -M – mai multe linii
  • "Pseudo.*\n.*42B.*\nstate.*" – se potrivește cu un grup de șiruri în care primul șir începe cu cuvântul "Pseudo" urmat de orice caractere până la sfârșitul liniei \n, urmat de orice caractere până până la șirul "42B" urmat de orice caractere până un alt capăt de linie (\n), urmat de șirul "state" urmat de orice caractere.

Comentarii

  • -C (context) poate fi folosit ca o comandă rapidă, dacă -A și -B sunt aceleași.
  • @DavidBaggerman – mulțumesc. L-am adăugat la răspuns.
  • De ce votul negativ? Aceasta răspunde la întrebare.

Răspunde

grep din unele arome ale Unix au semnalul -p pentru „paragraf”. Știu că face AIX .

grep -p 42B <myfile> 

ar face exact ceea ce cereți acolo . YMMV și GNU grep nu au acest semnal.

Comentarii

  • A avea semnalul -p ar fi minunat. Mai ales dacă este utilizat împreună cu -v, astfel încât să puteți exclude paragrafe întregi din ieșire.

Răspuns

Există probabil o modalitate ușor similară de a face acest lucru cu awk, dar în perl:

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

Asta spune practic să împărțiți fișierul în bucăți delimitate de linii goale, apoi să imprimați doar acele bucăți care se potrivesc cu expresia dvs. obișnuită. Comentarii

  • Acest lucru poate fi simplificat utilizând opțiuni și stenografii și pierzând utilizarea inutilă a cat ; perl -00 -ne 'print if /42B/' file

Răspuns

O altă soluție perl, fără o linie goală finală:

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

Exemplu

% 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 

Comentarii

  • Sau mai scurte (și, prin urmare, mai lizibile), după cum a scris triplee într-un comentariu: perl -00 -ne 'print if /42B/' file.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *