Как прочитать определенные строки после поиска текста?

12

Как я могу прочитать определенное количество строк после поиска текста?

Например.:

Прочитайте следующие 2 строки после поиска "Unix" на:

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

Результат может быть:

Test 5
Test 6

Примечание: «Unix» в последнем примере является аргументом, и поэтому это может быть любой другой текст.

Что я имею:

У меня все еще нет идей, нужен только свет. Думая о создании другого сценария, чтобы сделать это.

Холодный
источник

Ответы:

10

awkРешение:

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

объяснение

  • /^UNIX$/{i=1;next}: если мы видим UNIX, мы устанавливаем переменную i = 1, обрабатывая следующий ввод.

  • Если переменная iустановлена (то есть мы видели UNIX), i && i++ <= 2оценивается только к истинному значению в двух следующих строках после UNIX, в результате чего awkвыполняется действие по умолчанию print $0.

  • Перед тем как видим UNIX, iне был определен и начать на 3 - й линии после того, как UNIX, iимела большее значение , чем 2, что делает выражение оказалось i && i++ <= 2ложным, не вызывая awkничего не делать.

cuonglm
источник
После тестирования вы получаете решение, которое я получаю это сообщение об ошибке: systax ошибки рядом со строкой 1, выходящей из строя рядом со строкой 1
Cold
@ Холод: Что ты бежал? Обратите внимание, что $знак в начале моего ответа является приглашением оболочки, а не частью awkкоманды.
cuonglm
Другой вариант:awk '/^UNIX$/ {s=NR;next} s && NR<=s+2'
Musiphil
Я знаю, что @cuonglm
Холодная
@Cold: Какая у тебя ОС?
cuonglm
12

grepРешение:

grep -A2 -P '^UNIX$' file

Пояснение: -A означает: вывести следующие две строки после совпадения

Или awk:

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

Объяснение: Этот оператор ищет UNIX в строке ( $0=="UNIX"). Если это дано, он получает следующий следующий в свой буфер ( getline) и печатает буфер ( print). Это делается дважды.

Или используйте sed:

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

Объяснение: Это ищет для UNIX ( /^UNIX$/). Если это найдено, он выполняет часть в {...}. nозначает следующее, pзначит печать. Это сделано в два раза.

хаос
источник
Спасибо @chaos, я попробую последние 2 варианта, которые вы дадите. Пожалуйста, добавьте некоторые объяснения каждого варианта, я хочу согласиться и сделать.
Холодное
Если количество строк изменится, сколько изменений я сделаю в двух последних вариантах? Спасибо
Холод
@ Холод см. Мое редактирование. Чтобы изменить число, если строки повторяют getline; print;часть в awkвыписке или n;p;часть в sedвыписке.
хаос
Спасибо @chaos, но чем больше количество строк, тем больше выражение, и изменение, по моему мнению, неосуществимо. Тебе не кажется? Если 100 строк?
Холодное
@Cold Тогда я бы использовал решение grep с grep -A100 -P '^UNIX$' file | tail -n +2. Хвостовая часть предназначена для удаления первой селезенки. В других (sed, awk) вам придется писать циклы, что делает его менее простым.
хаос
4
grep -A 2 UNIX file.txt

Man-страница grep описывает эту опцию так:

  -A NUM, --after-context=NUM
      Print NUM  lines  of  trailing  context  after  matching  lines.
      Places  a  line  containing  --  between  contiguous  groups  of
      matches.
Twinkles
источник
Привет @ Twinkles, хороший ответ, но мой grep имеет только эту опцию "hblcnsviw". Но логика хороша. спасибо
Холодно
Это будет печатать и UNIXна выходе.
cuonglm
Чтобы опустить UNIX, трубы его tail: [...] | tail -n +1или sed: [...] | sed '1d'.
DopeGhoti
1
@ DopeGhoti: ваши предложения tailи sed '1d'предложения работают правильно только в том случае, если они UNIXпоявляются только один раз во входном тексте. Все остальные ответы допускают множественные вхождения. Может быть, лучше предложить ... | grep -v UNIX. По общему признанию, это становится грязным, если UNIXпоявляется в строках 15 и 17.
G-Man говорит: «Восстановите Монику»
Хорошие моменты. Я почти уверен, что это может быть сделано в sedкакой-то форме sed '/UNIX/d;n;n;p/' /path/to/file, которую я только что обдумал и представил в качестве ответа.
DopeGhoti
0

Кажется, это хорошо сработало:

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

Подтверждение концепции:

$ for i in {1..9}; do echo $i; done | sed -n '/4/{n;p;n;p}'
5
6
DopeGhoti
источник
1
Подоболочка вокруг вашей forпетли не нужна.
Приостановлено до дальнейшего уведомления.
На самом деле это не так; это был остаток какого-то другого фейерверка, на котором я был в тот момент на той скорлупе. Паренс удален.
DopeGhoti
0

Вы можете использовать ex:

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

где:

  • 1,/UNIX/d- удаляет текст после матча
  • %p - печатает буфер
  • q!- выйти без сохранения изменений в файл (используйте wqдля редактирования на месте)
kenorb
источник