Zwraca tylko część linii po pasującym wzorcu


109

Więc pociągnięcie do otwarcia pliku za pomocą, cata następnie użycie grepdo uzyskania pasujących linii prowadzi mnie tylko do tej pory, gdy pracuję z określonym zestawem dzienników, z którym mam do czynienia. Potrzebuje sposobu, aby dopasować linie do wzoru, ale tylko zwrócić część linii po dopasowaniu. Część przed i po meczu będzie się stale różnić. Grałem przy użyciu sedlub awk, ale nie byłem w stanie dowiedzieć się, jak filtrować wiersz, aby usunąć część przed meczem lub po prostu zwrócić część po meczu, albo zadziała. To jest przykład linii, którą muszę filtrować:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

Porcja, której potrzebuję, to wszystko po „utknięciu w martwym punkcie”.

Tłem tego jest to, że mogę dowiedzieć się, jak często coś się zatrzymuje:

cat messages | grep stalled | wc -l

Muszę dowiedzieć się, ile razy jakiś węzeł utknął (wskazany przez część przed każdym dwukropkiem po „utknięciu w martwym punkcie”). Jeśli po prostu grepuję za to (tj. 20 :), może zwrócić linie, które mają soft, ale zawodzą, ale żadnych przeciągnięć, co mi nie pomaga. Muszę odfiltrować tylko zatrzymany odcinek, aby móc grepować dla określonego węzła z zatrzymanych.

Pod każdym względem jest to system freebsd ze standardowymi narzędziami GNU, ale nie mogę zainstalować niczego dodatkowego, aby pomóc.


@Gilles, Dziwne, jak to nie wyskoczyło podczas wyszukiwania, chociaż nie użyłem tytułu, z którym ostatecznie poszedłem ... ale nie pojawił się na ekranie poniżej mojego tytułu. W każdym razie, poza tym, może zabrać mnie tam, gdzie chcę, chociaż potrzebuję całej linii po meczu, a nie pierwszego słowa - ale może nie wymagać dużej zmiany.
MaQleod,

Jego tytuł był do kitu. Ukradłem twoje, co jest bardzo miłe. Weź sedrozwiązanie i nie traktuj specjalnie białych znaków.
Gilles,

@Gilles, to jest coś, czego nie jestem całkowicie pewien, jak to zrobić. Nadal uczę się sed.
MaQleod,


1
@ shaa0601 Nie rozumiem twojego pytania, szczególnie trudno jest odpowiedzieć w komentarzu bez formatowania. Zadaj nowe, samodzielne pytanie.
Gilles

Odpowiedzi:


141

Kanonicznym narzędziem do tego byłoby sed.

sed -n -e 's/^.*stalled: //p'

Szczegółowe wyjaśnienie:

  • -n oznacza domyślnie brak drukowania.
  • -e po nim następuje polecenie sed.
  • s to polecenie zamiany wzorca.
  • Wyrażenie regularne ^.*stalled:pasuje do szukanego wzorca oraz do dowolnego poprzedzającego tekstu ( .*co oznacza dowolny tekst, z inicjałem ^mówiącym, że dopasowanie zaczyna się na początku wiersza). Zauważ, że jeśli stalled:wystąpi kilka razy w linii, będzie pasować do ostatniego wystąpienia.
  • Dopasowanie, tzn. Wszystko w wierszu do stalled:, jest zastępowane pustym ciągiem (tzn. Usuwane).
  • Ostatni psposób drukowania przekształconej linii.

Jeśli chcesz zachować pasującą część, użyj odnośnika zwrotnego: \1w części zamiennej oznacza to, co znajduje się w grupie \(…\)we wzorcu. Tutaj można napisać stalled:ponownie w ramach zastępczej; ta funkcja jest przydatna, gdy szukany wzór jest bardziej ogólny niż zwykły ciąg.

sed -n -e 's/^.*\(stalled: \)/\1/p'

Czasami będziesz chciał usunąć fragment linii po meczu. Możesz uwzględnić go w dopasowaniu, umieszczając go .*$na końcu wzorca (dowolny tekst, .*po którym następuje koniec linii $). O ile nie umieścisz tej części w grupie, do której się odwołujesz w tekście zastępczym, koniec wiersza nie będzie w wyniku.

Jako kolejna ilustracja grup i odnośników wstecz, to polecenie zamienia część przed meczem i część po meczu.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

Wypróbowałem dwa pierwsze przykłady i wydaje się, że po prostu się zawiesił. Nie otrzymuję komunikatu o błędzie ani nowego monitu, nic.
MaQleod

2
@MaQleod Och, czeka na wejście na standardowym wejściu, którym jest terminal, ponieważ go nie przekierowałeś. Tutaj można by zrobić przekierowanie sygnału wejściowego sed … <messages, ponieważ chcesz przetwarzać dane z pliku. Działać na danych dostarczonych przez innego polecenia, można użyć rury: somecommand | sed ….
Gilles

1
właśnie tam, koniec dnia zaciemnienie. polecenie działa idealnie, dzięki.
MaQleod,

1
Najlepsze wyjaśnienie sed, jakie do tej pory widziałem - dzięki!
Jon Wadsworth

1
@ungalcrys Krótsza wersja czego? To nie jest równoważne żadnemu z poleceń w mojej odpowiedzi. Polecam napisanie go, sed 's/^.*stalled//'ponieważ -rjest on specyficzny dla Linuksa i nie działa na innych systemach, takich jak macOS, a tutaj nie zyskujesz z tego żadnych korzyści.
Gilles

72

Inne narzędzie kanoniczne, którego już używasz grep:

Na przykład:

grep -o 'stalled.*'

Ma taki sam wynik jak druga opcja Gillesa:

sed -n -e 's/^.*\(stalled: \)/\1/p'

-oFlag zwraca --only-matchingczęść wyrażenia, więc nie cała linia jest - oczywiście - zazwyczaj wykonywane przez grep.

Aby usunąć „stalled:” z wyjścia, możemy użyć trzeciego narzędzia kanonicznego, wytnij:

grep -o 'stalled.*' | cut -f2- -d:

cutKomenda używa ogranicznika :i drukuje Pole 2 do końca. Oczywiście jest to kwestia preferencji, ale cutskładnię, którą uważam za bardzo łatwą do zapamiętania.


1
Dziękujemy za podanie -oopcji! Chciałem zaznaczyć, że grepnie rozpoznaje \nnowego wiersza, więc twój pierwszy przykład pasuje tylko do pierwszego nznaku. Na przykład echo "Hello Anne" | grep -o 'A[^\n]*'zwraca ciąg A. Jednak echo "Hello Anne" | grep -o 'A.*'zwraca oczekiwany Anne, ponieważ .dopasowuje dowolny znak oprócz znaku nowej linii.
adamlamar

1
Zauważ, że cudzysłowy wokół cutogranicznika -d':'są usuwane przez @poige. Łatwiej zapamiętać z cytatami, np. Z -d' 'lub -d';'.
Anne van Rossum,

Według twoich ustaleń łatwiej jest pamiętać o używaniu cytatów -f 2. Poważnie, dlaczego nie?
poige

Ponieważ separator taki jak średnik ;zamiast dwukropka :będzie interpretowany inaczej, jeśli nie będzie cytowany. Oczywiście to logiczne zachowanie, ale nadal lubię polegać na pamięci mięśniowej. Nie lubię cytować ogranicznika raz, ale nie raz. Po prostu osobiste preferencje, jak powiedziałem wcześniej: łatwiej zapamiętać.
Anne van Rossum,

okres, który jest częścią .*jest potrzebna, działa dobrze dla mnie: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' powrotyxyz text
RON

4

Zwykłem ifconfig | grep eth0 | cut -f3- -d:to brać

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

i spraw, aby wyglądało to tak

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
Czy to odpowiada na pytanie?
Stephen Rauch

1
Możesz użyć cat /sys/class/net/*/address, nie wymaga analizy.
Anne van Rossum,

1

Jeszcze jedno narzędzie kanoniczne, które rozważałeś, awkmoże być użyte w następującym wierszu:

awk -F"stalled" '/stalled/{print $2}' messages

Szczegółowe wyjaśnienie:

  • -Fdefiniuje separator dla linii, tzn. „utknął w martwym punkcie”. Wszystko przed separatorem jest adresowane $1i wszystko po nim $2.
  • /reg-ex/ Wyszukuje pasujące wyrażenie regularne, w tym przypadku „utknął w martwym punkcie”.
  • {print $<n>}- drukuje n kolumnę. Ponieważ separator jest zdefiniowany jako przeciągnięty, wszystko po zablokowaniu jest uważane za drugą kolumnę.
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.