Jak czytać niektóre wiersze po znalezieniu tekstu?


12

Jak mogę odczytać określoną liczbę wierszy po znalezieniu tekstu?

Na przykład.:

Czytaj kolejne 2 linie po znalezieniu „Unixa” na:

Test 1
Test 2
Test 3
Test 4
UNIX
Test 5
Test 6
Test 7
Test 8
Test 9

Wynik może być:

Test 5
Test 6

Uwaga: „Unix” w ostatnim przykładzie jest argumentem, więc może to być dowolny inny tekst.

Co ja mam:

Wciąż brakuje mi pomysłów, potrzebuję tylko światła. Zastanawiając się nad stworzeniem kolejnego skryptu, aby to zrobić.

Odpowiedzi:


10

awkRozwiązanie:

$ awk '$0 == "UNIX" {i=1;next};i && i++ <= 2' file
Test 5
Test 6

Wyjaśnienie

  • /^UNIX$/{i=1;next}: jeśli zobaczymy UNIX, ustawiamy zmienną i = 1, przetwarzając do następnego wejścia.

  • Jeśli zmienna ijest ustawiona (co oznacza, że ​​widzieliśmy UNIX), jest i && i++ <= 2przetwarzana tylko na prawdziwą wartość w kolejnych dwóch wierszach po UNIX, powodując awkdomyślną akcję print $0.

  • Przed zobaczeniem UNIX, inie został zdefiniowany i zaczynał od 3 linii po UNIX, imiał wartość większą niż 2, co powoduje, że wyrażenie jest i && i++ <= 2oceniane na false, powodując, że awknic nie rób.


Po przetestowaniu rozwiązania otrzymuję ten komunikat o błędzie: błąd systax w pobliżu linii 1 wyskakuje w pobliżu linii 1
Cold

@Cold: Co prowadziłeś? Zauważ, że $znak na początku mojej odpowiedzi jest pytaniem powłoki, a nie częścią awkpolecenia.
cuonglm

Kolejny wariant:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
musiphil

Wiem, że @cuonglm
Cold

@Cold: Jaki jest twój system operacyjny?
cuonglm

12

grepRozwiązanie:

grep -A2 -P '^UNIX$' file

Objaśnienie: -A oznacza: wydrukuj kolejne dwa wiersze po meczu

Lub awk:

awk '$0=="UNIX"{getline; print; getline; print}' file

Objaśnienie: Ta instrukcja szuka UNIX w wierszu ( $0=="UNIX"). Jeśli tak, pobiera następny do bufora ( getline) i drukuje bufor ( print). Odbywa się to dwukrotnie.

Lub użyj sed:

sed -n '/^UNIX$/{n;p;n;p}' file

Objaśnienie: Wyszukuje dla UNIX ( /^UNIX$/). Jeśli to zostanie znalezione, txecuts część w {...}. noznacza następnie poznacza druk. Odbywa się to również dwukrotnie.


Dzięki @chaos, spróbuję 2 ostatnie opcje, które dajesz. Proszę załączyć wyjaśnienie każdej opcji, nie będę się zgadzać i zrobić.
Zimny

Jeśli zmieni się liczba wierszy, ile zmian wprowadzę dla dwóch ostatnich opcji? Dzięki
Cold

@Cold zobacz moją edycję. Aby zmienić liczbę, jeśli wiersze powtarzają getline; print;część w awkinstrukcji lub n;p;część w sedinstrukcji.
chaos

Dzięki @chaos, ale im większa liczba wierszy, tym większa ekspresja i zmiana nie jest moim zdaniem możliwa. Nie myślisz, że? Jeśli 100 linii?
Zimny

@Cold Następnie użyłbym rozwiązania grep grep -A100 -P '^UNIX$' file | tail -n +2. Część ogonowa polega na usunięciu pierwszego zastawu. W pozostałych (sed, awk) trzeba pisać pętle, co czyni to mniej prostym.
chaos

4
grep -A 2 UNIX file.txt

Strona man grep opisuje opcję w ten sposób:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.

Cześć @Twinkles, dobra odpowiedź, ale mój grep ma tylko te opcje „hblcnsviw”. Ale logika jest dobra. dzięki
Cold

To również wydrukuje UNIXdane wyjściowe.
cuonglm

Pominięcie UNIX, rury do tail: [...] | tail -n +1lub sed: [...] | sed '1d'.
DopeGhoti

1
@DopeGhoti: twoje taili sed '1d'sugestie działają poprawnie tylko wtedy, gdy UNIXpojawia się tylko raz w tekście wejściowym. Wszystkie pozostałe odpowiedzi pozwalają na wiele wystąpień. Lepiej byłoby zasugerować ... | grep -v UNIX. Wprawdzie robi się bałagan, jeśli UNIXpojawia się w wierszach 15 i 17.
G-Man mówi „Przywróć Monikę”

Słuszne uwagi. Jestem prawie pewien, że można to zrobić za sedpomocą jakiejś formy sed '/UNIX/d;n;n;p/' /path/to/file, o której właśnie przesądziłem i podałem jako odpowiedź.
DopeGhoti

0

Wydaje się, że robi to dobrze:

sed -n '/UNIX/{n;p;n;p}' /path/to/file

Dowód koncepcji:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6

1
Warstwa wewnętrzna wokół forpętli nie jest konieczna.
Wstrzymano do odwołania.

Rzeczywiście tak nie jest; była to pozostałość jakiegoś innego faffery, w którym byłem w środku tej skorupy wcześniej tego samego dnia. Parens usunięte.
DopeGhoti

0

Możesz użyć ex:

ex -s +'1,/UNIX/d|%p|q!' file_or_/dev/stdin

gdzie:

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.