Вывести строку соответствия и n-ю строку из строки соответствия

18

Я пытаюсь распечатать совпавшую строку и четвертую строку из совпавшей строки (строка, содержащая искомое выражение).

Я использовал следующий код: sed -n 's/^[ \t]*//; /img class=\"devil_icon/,4p' input.txt

Но это только печатает согласованную линию.

Это печатает только 4-ую строку. awk 'c&&!--c;/img class=\"devil_icon/{c=4}' input.txt

Мне нужно напечатать как совпадающую строку, так и только 4-ю строку.

Debal
источник
Использование egrep "pattern" -A4
Валентин Байрами
@ val0x00ff, который также печатает строки между ними .. то есть: он печатает следующие 4 строки, начиная с совпавшей строки
дебал
Вы говорите: «Я пытаюсь напечатать соответствующую строку и 4-ую строку из соответствующей линии». Это grep -A 4 "pattern" file | sed -n '4p'делает именно то, что вы хотите, если я не понимаю вас
Валентин Баджрами
нет, это не так. Вывод вышеприведенного кода был </td>не 4-й строкой
дебал

Ответы:

18

В awk вы бы сделали это следующим образом

awk '/pattern/{nr[NR]; nr[NR+4]}; NR in nr' file > new_file`

или

awk '/pattern/{print; nr[NR+4]; next}; NR in nr' file > new_file`

объяснение

Первое решение находит все совпадающие строки pattern. Когда он находит совпадение, он сохраняет номер записи ( NR) в массиве nr. Он также хранит 4-ую запись NRв том же массиве. Это сделано nr[NR+4]. Каждая запись ( NR) затем проверяется, чтобы увидеть, присутствует ли она в nrмассиве, если это так, запись распечатывается.

Второе решение работает, по сути, таким же образом, за исключением того, что когда оно встречает, patternпечатает эту строку, а затем сохраняет четвертую запись перед ней в массиве nr, а затем переходит к следующей записи. Затем, когда awkвстретится с этой 4-й записью, NR in nrблок будет выполнен и напечатает эту запись +4 после этого.

пример

Вот пример файла данных sample.txt.

$ cat sample.txt 
1
2
3
4 blah
5
6
7
8
9
10 blah
11
12
13
14
15
16

Используя 1-е решение:

$ awk '/blah/{nr[NR]; nr[NR+4]}; NR in nr' sample.txt 
4 blah
8
10 blah
14

Используя 2-е решение:

$ awk '/blah/{print; nr[NR+4]; next}; NR in nr' sample.txt 
4 blah
8
10 blah
14
Валентин Байрами
источник
3
Ницца +1. Здесь вы используете много awkярлыков, не могли бы вы добавить краткое объяснение (такие вещи, как печать, подразумевается в awk, массивы ассоциативны и т. Д.)?
Тердон
согласен с @terdon, пожалуйста, не могли бы вы немного объяснить код.
Дебаль
@slm Спасибо за улучшение и полный ответ!
Валентин Байрами,
1
Спасибо за ответ, я тоже кое-что узнал.
SLM
4
sed -n 's/^[ \t]*/; /img class=\"devil_icon/,+4 { 3,5d ; p }' input.txt

Я просто добавляю удаление соответствующих строк перед печатью { 3,5d ; p }.

Драв Слоан
источник
Ваше выражение выдает ошибку: sed: -e expression #1, char 18: unknown option to s'`
минералы
4

Вы можете попробовать -Aпараметр с grep, который определяет, сколько строк после соответствующей строки должно быть напечатано. Соедините это с sed, и вы получите необходимые строки.

grep -A 4 pattern input.txt | sed -e '2,4d'

Используя sed, мы удаляем из второй строки до четвертой.

Барун
источник
3
Это предполагает одно совпадение patternв файле.
Тердон
2

Вот способ в Perl, который может иметь дело с произвольным числом совпадающих строк:

perl -ne '/pattern/ && do{$c=$.; print}; $.==$c+4 && print' file > new_file`

В перл. специальная переменная $.- текущий номер строки. Поэтому каждый раз, когда я нахожу совпадение строк pattern, я печатаю его и сохраняю номер строки как $c. Затем я печатаю снова, когда номер текущей строки на 4 больше, чем напечатанный ранее.

Тердон
источник
0
awk 'c&&!--c;/img class=\"devil_icon/{c=4};/img class=\"devil_icon/' input.txt

По сути, вы делаете поиск и замену. Вы можете добавить просто находку в одну и ту же команду, и она выведет их обоих :)

awk 'c&&!--c;/pattern/{c=4};/pattern/' input.txt
bacoNx1000
источник