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

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

Ответ 1

У меня все получится.

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

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

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

sed -e '/pattern/{n;N;N;N;N;d}' file.txt

Ответ 2

Простые решения 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 по умолчанию печатает строку.

Ответ 3

Это решение позволяет вам передать "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 -

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

Ответ 4

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

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