Poniżej znajduje się tekst w pliku:

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

Muszę grepować „42B” i uzyskaj wynik z powyższego tekstu, taki jak:

Pseudo name=Apple Code=42B state=fault 

Czy ktoś ma pomysł, jak to osiągnąć za pomocą grep / awk / sed?

Komentarze

  • Oznaczyłeś to pytanie tylko tagiem " grep ". Czy zatem szukasz tylko rozwiązań " grep "? W pytaniu określasz również awk & sed. Czy możemy dodać te tagi? Nie byłem ' pewien twojego zamiaru, kiedy edytowałem pytanie zeszłej nocy.
  • stackoverflow.com/ pytania / 12024410 / …

Odpowiedź

Z awk

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

RS= zmienia separator rekordów wejściowych od nowej linii do pustych linii. Jeśli którekolwiek pole w rekordzie zawiera /42B/, wydrukuj rekord.

"" (ciąg pusty) to magia wartość używana do reprezentowania pustych linii zgodnie z POSIX :

Jeśli RS ma wartość null, a następnie rekordy są oddzielone sekwencjami składającymi się z <newline> plus co najmniej jednego pustego wiersze, początkowe lub końcowe puste wiersze nie powodują pustych rekordów na początku ani na końcu danych wejściowych, a <newline> zawsze będzie separatorem pól, bez względu na wartość FS is.

Wyjściowe akapity nie będą być oddzielone, ponieważ separatorem wyjściowym pozostaje pojedynczy znak nowej linii. Aby upewnić się, że między wyjściowymi akapitami jest pusty wiersz, ustaw separator rekordu wyjściowego na dwie nowe linie:

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

Komentarze

  • +1 za eleganckie rozwiązanie. Nie ' nie musisz jednak przekierowywać pliku …
  • palce były na autopilocie.
  • @jasonwryan, chyba że potrzebujesz dostępu do nazwy pliku w awk (FILENAME), ' nie jest złym pomysłem użycie przekierowania, ponieważ pozwala to uniknąć problemów z nazwą pliku zawierającą = lub zaczynające się od - (lub -), zapewnia spójne komunikaty o błędach oraz unika uruchamiania awk lub wykonywania innych przekierowań, jeśli plik wejściowy nie może ' t zostać otwarty.

Odpowiedź

Zakładając, że dane są ustrukturyzowane w taki sposób, że zawsze jest to linia przed i po, którą chcesz, możesz użyć grep „s -A (po) i -B (przed) przełącza się, aby poinformować go, aby zawierał 1 linię przed dopasowaniem i 1 linię po niej:

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

Jeśli chcesz, aby tę samą liczbę wierszy przed i po wyszukiwanym haśle możesz użyć przełącznika -C (kontekst):

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

Jeśli chcesz być bardziej rygorystyczny przy dopasowywaniu wielu wierszy, możesz użyć narzędzia pcregrep , aby dopasować wzorzec w wielu wierszach:

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

Powyższy wzorzec pasuje w następujący sposób:

  • -M – wiele linii
  • "Pseudo.*\n.*42B.*\nstate.*" – dopasowuje grupę ciągów, w których pierwszy ciąg zaczyna się od słowa "Pseudo" po którym następują dowolne znaki aż do końca wiersza \n, po którym następują dowolne znaki aż do ciągu "42B", po którym następują dowolne znaki aż do kolejny koniec wiersza (\n), po którym następuje ciąg "state", po którym następują dowolne znaki.

Komentarze

  • (kontekst) może służyć jako skrót, jeśli -A i -B są takie same.
  • @DavidBaggerman – dzięki. Dodałem go do odpowiedzi.
  • Dlaczego ten jeden nie zagłosował? To odpowiada na pytanie.

Odpowiedź

grep z niektóre odmiany Uniksa mają flagę -p dla „akapitu”. Wiem, że AIX robi .

grep -p 42B <myfile> 

zrobiłby dokładnie to, o co prosisz . YMMV i GNU grep nie mają tej flagi.

Komentarze

  • Posiadanie flagi -p byłoby cudowne. Szczególnie jeśli jest używane razem z -v, więc możesz wykluczyć całe akapity z wyjścia.

Odpowiedź

Prawdopodobnie jest podobnie łatwy sposób na zrobienie tego w awk, ale w perlu:

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

Oznacza to, że należy podzielić plik na fragmenty oddzielone pustymi wierszami, a następnie wydrukować tylko te fragmenty, które pasują do wyrażenia regularnego.

Komentarze

Odpowiedź

Inne rozwiązanie w Perlu, bez końcowa pusta linia:

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

Przykład

% 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 

Komentarze

  • Lub krótsze (a przez to bardziej czytelne), jak triplee napisał w komentarzu: perl -00 -ne 'print if /42B/' file.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *