Найти совпадения на смежных линиях

Я хочу найти соседние совпадающие строки, например, если совпадение шаблона

$ grep -n pattern file1 file2 file3 file1:10: ... file2:100: ... file2:1000: ... file2:1001: ... file3:1: ... file3:123: ... 

Я хочу найти средние два матча:

 file2:1000: ... file2:1001: ... 

но не первые два и два последних.

4 Solutions collect form web for “Найти совпадения на смежных линиях”

Я буду использовать тот же файл теста, что и трэк:

 $ cat file a pat 1 pat 2 b pat 3 

Вот решение awk:

 $ awk '/pat/ && last {print last; print} {last=""} /pat/{last=$0}' file pat 1 pat 2 

Как это работает

awk неявно перебирает каждую строку в файле. Эта программа использует одну переменную, last , которая содержит последнюю строку, если она соответствует регулярному выражению. В противном случае он содержит пустую строку.

  • /pat/ && last {print last; print}

    Если pat соответствует этой строке, а предыдущая строка, last , была также совпадением, а затем печатать обе строки.

  • {last=""}

    Заменить last пустую строку

  • /pat/ {last=$0}

    Если эта строка соответствует pat , то установите last в эту строку. Таким образом, он будет доступен, когда мы обработаем следующую строку.

Альтернатива для лечения> 2 последовательных матча как одна группа

Рассмотрим этот расширенный тестовый файл:

 $ cat file2 a pat 1 pat 2 b pat 3 c pat 4 pat 5 pat 6 d 

В отличие от вышеприведенного решения, этот код рассматривает три последовательные строки соответствия как одну группу для печати:

 $ awk '/pat/{f++; if (f==2) print last; if (f>=2) print; last=$0; next} {f=0}' file2 pat 1 pat 2 pat 4 pat 5 pat 6 

Этот код использует две переменные. Как и прежде, last – предыдущая строка. Кроме того, f подсчитывает количество последовательных совпадений. Итак, мы печатаем соответствующие строки, когда f равно 2 или больше.

Добавление grep-подобных функций

Чтобы эмулировать вывод grep указанный в вопросе, эта версия печатает имя файла и номер строки перед каждой соответствующей строкой:

 $ awk 'FNR==1{f=0} /pat/{f++; if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last; if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0; last=$0; next} {f=0}' file file2 file:2:pat 1 file:3:pat 2 file2:2:pat 1 file2:3:pat 2 file2:7:pat 4 file2:8:pat 5 file2:9:pat 6 

Переменные Awk FILENAME предоставляют имя файла, а FNR awk предоставляет номер строки в файле.

В начале каждого файла, FNR==1 , мы перезапускаем f до нуля. Это препятствует тому, чтобы последняя строка одного файла считалась последовательной с первой строкой следующего файла.

Для тех, кто любит свой код, разбросанный по нескольким строкам, вышесказанное выглядит так:

 awk ' FNR==1{f=0} /pat/ {f++ if (f==2) printf "%s:%s:%s\n",FILENAME,FNR-1,last if (f>=2) printf "%s:%s:%s\n",FILENAME,FNR,$0 last=$0 next } {f=0} ' file file2 

Один из способов – сохранить предыдущую строку и напечатать, когда текущая и предыдущая строка совпадают:

 bash-4.1$ (echo a; echo pat 1; echo pat 2; echo b; echo pat 3) a pat 1 pat 2 b pat 3 bash-4.1$ (echo a; echo pat 1; echo pat 2; echo b; echo pat 3) | \ perl -nle 'print "$prev\n$_" if /pat/ and $prev =~ /pat/; $prev=$_' pat 1 pat 2 

Это, однако, приведет к дублированию совпадений, если будет три или более смежных строк, которые соответствуют, так как они будут совпадать по очереди два или более раз. Лучшим вариантом было бы отслеживать количество предыдущих строк, которые соответствуют, а также написать некоторый тестовый код, чтобы подтвердить, что обрабатываются различные случаи крайнего края (например, блок вверх к концу файла).

 #!/usr/bin/env perl use strict; use warnings; my $prev; my $pattern = qr/pat/; my $have_matches = 0; while (my $line = readline) { if ($line =~ /$pattern/) { print $prev if $have_matches == 1; print $line if $have_matches; $have_matches++; $prev = $line; } else { $have_matches = 0; } } 

Для записи вы также можете сделать это с помощью sed :

 sed -s '$!N /.*PATTERN.*\n/{/\n.*PATTERN/{x;/^1$/!s/.*/1/;bv};//!{x;/^1$/{s/./0/;bv};//!D}} //!{${/PATTERN/{x;/^1$/{bv}}};D;};: v;x;P;D' file1 file2 ... fileN 

Это gnu sed . С другими sed вам придется обрабатывать один файл за раз:

 sed '$!N # if not on the last line pull in the next line /.*PATTERN.*\n/{ # if first line in the pattern space matches /\n.*PATTERN/{ # and if second line also matches x # exchange pattern space with hold buffer /^1$/!s/.*/1/ # replace everything with 1 bv # branch to label v } //!{ # if second line does not match x # exchange pattern space with hold buffer /^1$/{ # if it matches 1 s/.*/0/ # replace with 0 bv # branch to label v } //!D # if it does not match 1 delete up to first newline } } //!{ # if first line does not match ${ # if we're on the last line /PATTERN/{ # and if it matches x # exchange pattern space with hold buffer /^1$/{ # if it matches 1 bv # branch to label v } } } D # else delete up to first newline } : v # label v x # exchange pattern space with hold buffer P # print up to first newline D' infile # delete up to first newline 

Это не так гибко, как perl или awk хотя вы не можете полностью эмулировать выход grep т. Е. Префиксные строки с именем файла и номером строки, хотя с помощью gnu sed вы можете получить имя файла, добавив F до P а затем проложив весь вывод на paste -d: - -

Привет, есть различные команды, которые могут помочь вам в прекрасной последней строке попробовать это ..

 <grep command> | tail -1 

или

 awk '/result/ { save=$0 }END{ print save }' filename 
  • Согласование и вставка в линию
  • Редактирование вложенного текста и определенных строк в файле с использованием сценария bash
  • Прочитайте строку из файла и добавьте ее в ту же строку другого файла
  • Простое использование суффикса адресной строки '/ M'?
  • Tail Grep - печать окружающих линий до тех пор, пока шаблон не будет сопоставлен
  • вставка текста между двумя строками
  • Как извлечь одно значение из однострочных кортежей?
  • Ошибка `sed` regexp
  • Разделение строки до определенного места
  • Как сделать URL из этого текста с наименьшими ресурсами?
  • Заменить значение в таблице
  • Параллелизация sed дает разную производительность
  • Linux и Unix - лучшая ОС в мире.