sed или awk: удалить n строк по шаблону

106

Как мне смешивать шаблоны и числовые диапазоны в sed (или другом подобном инструменте - например, awk)? Я хочу сопоставить определенные строки в файле и удалить следующие n строк перед тем, как продолжить, и я хочу сделать это как часть конвейера.

Мартин ДеМелло
источник

Ответы:

189

Я попробую это сделать.

Чтобы удалить 5 строк после шаблона (включая строку с шаблоном):

sed -e '/pattern/,+5d' file.txt

Чтобы удалить 5 строк после узора (исключая строку с узором):

sed -e '/pattern/{n;N;N;N;N;d}' file.txt
кендырь
источник
14
Обратите внимание, что этот +Nшаблон является расширением GNU. Измените первый nна Nвторой во втором примере, чтобы он включал линию с узором.
Приостановлено до дальнейшего уведомления.
2
как удалить все строки после совпадения с шаблоном? Я использую sed -e '/ <! - # content end -> </div> /, $ d' out.txt, но выдает сообщение об ошибке: sed: -e выражение # 1, char 24: дополнительные символы после command Заранее спасибо.
N mol
8
То, что происходит, похоже, но в каждом случае немного отличается. В первом рецепте /pattern/,+5определяет диапазон, который начинается со строки, содержащей «шаблон» ( /pattern/), и заканчивается на 5 строк позже ( +5). Последний символ d- это команда, запускаемая в каждой строке в этом диапазоне, то есть «удалить». Во втором рецепте вместо сопоставления диапазона он сопоставляется только со строкой, содержащей шаблон ( /pattern/), а затем запускает серию команд:, {n;N;N;N;N;d}которая в основном печатает следующую строку ( n), а затем считывает и, наконец, отбрасывает следующие 4 строки ( N;N;N;N;d).
pimlottc 02
18
В системах Mac / OS X вам нужно добавить точку с запятой перед закрывающей скобкой:sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
AvL
1
Для полноты: Чтобы удалить все строки, следующие определенному шаблону, something выполните:, sed -E '/^something$/,$d'где -E- расширенное регулярное выражение переносимости POSIX.
not2qubit
7

Без расширений GNU (например, в macOS):

Чтобы удалить 5 строк после шаблона (включая строку с шаблоном)

 sed -e '/pattern/{N;N;N;N;d;}'

Добавить -i ''для редактирования на месте.

тхаки
источник
6

Простые awkрешения:

Предположим, что регулярное выражение, используемое для поиска совпадающих строк, хранится в переменной оболочки $regex, а количество строк, которые нужно пропустить $count.

Если совпадающая строка также должна быть пропущена ( $count + 1строки пропускаются):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'

Если совпавшая строка должна не быть пропущена ( $countстроки после матча пропускается):

... | awk -v regex="$regex" -v count="$count" \
  '$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'

Пояснение:

  • -v regex="$regex" -v count="$count"определяет awkпеременные на основе одноименных переменных оболочки .
  • $0 ~ regex соответствует интересующей линии
    • { skip=count; next }инициализирует счетчик пропусков и переходит к следующей строке, фактически пропуская соответствующую строку; во втором решении printпредыдущий nextгарантирует, что он не будет пропущен.
    • --skip >= 0 уменьшает счетчик пропусков и принимает меры, если он (все еще)> = 0, что означает, что данную строку следует пропустить.
    • { next } переходит к следующей строке, фактически пропуская текущую строку
  • 1это обычно используемое сокращение для { print }; то есть текущая строка просто печатается
    • До этой команды доходят только несоответствующие и непропущенные строки.
    • Причина, которая 1эквивалентна, { print }заключается в том, что 1она интерпретируется как логический шаблон, который по определению всегда принимает значение true, что означает, что связанное с ним действие (блок) выполняется безоговорочно. Поскольку в этом случае нет связанных действий, по awkумолчанию выполняется печать строки.
mklement0
источник
3

Это может сработать для вас:

cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1 
2
3
4
5
9
10
12
13
14
15
21
Potong
источник
10
Вау, это загадочно.
pimlottc 02
3
Умное (хотя и специфичное для GNU-Sed) решение, но мало кому оно поможет, если вы не добавите объяснение. pattern_number.txt- это файл с двумя столбцами, содержащий шаблон для сопоставления в первом столбце, а во втором - количество строк, которые необходимо пропустить. Первая sedкоманда преобразует файл в sedсценарий, который выполняет соответствующее сопоставление и пропуск; этот сценарий предоставляется второй командой через -fstdin ( -) sed. Вторая sedкоманда работает с образцом специального входного файла, сформированного из выходных данных, seq 21чтобы продемонстрировать, что он работает.
mklement0
Кроме того, решение имеет одну оговорку: метод, который он использует, чтобы не пропускать первую строку (ту, которая соответствует шаблону), имеет побочный эффект, а также не пропускает повторяющиеся строки в диапазоне.
mklement0
Это впечатляющее использование sed.
Трэвис Родман
3

Использование Perl

$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$.  if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$
стек0114106
источник
2

Это решение позволяет вам передавать "n" в качестве параметра, и оно будет читать ваши шаблоны из файла:

awk -v n=5 '
    NR == FNR {pattern[$0]; next}
    {
        for (patt in pattern) {
            if ($0 ~ patt) {
                print # remove if you want to exclude a matched line
                for (i=0; i<n; i++) getline
                next
            }
        }
        print
    }
' file.with.patterns -

Файл с именем «-» означает стандартный ввод для awk, поэтому он подходит для вашего конвейера.

Гленн Джекман
источник
2
awk может быть намного более похожим на Perl, чем я думал!
Мартин ДеМелло