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

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

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

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

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

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

  • Какая версия sed не является GNU sed 4.0?
  • Смешанное прописное и строчное слово в слове
  • Необходимо удалить - (минус) знак в конце в количестве из многих столбцов и вставить его на удаленные столбцы
  • Удалить строки из файла с разделителями табуляции с отсутствующими значениями
  • sed backreference: получить каждую строку и добавить ее к концу строки
  • Перемещение строк данных в один столбец при сохранении заголовков строк
  • Заменить соответствия многострочной строкой с помощью sed
  • Использование sed для замены пробелов в текстовых файлах _ только тогда, когда между "" после определенной строки
  • 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 
    Linux и Unix - лучшая ОС в мире.