Как мне смешивать шаблоны и числовые диапазоны в sed (или другом подобном инструменте - например, awk)? Я хочу сопоставить определенные строки в файле и удалить следующие n строк перед тем, как продолжить, и я хочу сделать это как часть конвейера.
Как мне смешивать шаблоны и числовые диапазоны в sed (или другом подобном инструменте - например, awk)? Я хочу сопоставить определенные строки в файле и удалить следующие n строк перед тем, как продолжить, и я хочу сделать это как часть конвейера.
Ответы:
Я попробую это сделать.
Чтобы удалить 5 строк после шаблона (включая строку с шаблоном):
sed -e '/pattern/,+5d' file.txt
Чтобы удалить 5 строк после узора (исключая строку с узором):
sed -e '/pattern/{n;N;N;N;N;d}' file.txt
/pattern/,+5
определяет диапазон, который начинается со строки, содержащей «шаблон» ( /pattern/
), и заканчивается на 5 строк позже ( +5
). Последний символ d
- это команда, запускаемая в каждой строке в этом диапазоне, то есть «удалить». Во втором рецепте вместо сопоставления диапазона он сопоставляется только со строкой, содержащей шаблон ( /pattern/
), а затем запускает серию команд:, {n;N;N;N;N;d}
которая в основном печатает следующую строку ( n
), а затем считывает и, наконец, отбрасывает следующие 4 строки ( N;N;N;N;d
).
sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
something
выполните:, sed -E '/^something$/,$d'
где -E
- расширенное регулярное выражение переносимости POSIX.
Простые 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
умолчанию выполняется печать строки.Это может сработать для вас:
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
pattern_number.txt
- это файл с двумя столбцами, содержащий шаблон для сопоставления в первом столбце, а во втором - количество строк, которые необходимо пропустить. Первая sed
команда преобразует файл в sed
сценарий, который выполняет соответствующее сопоставление и пропуск; этот сценарий предоставляется второй командой через -f
stdin ( -
) sed
. Вторая sed
команда работает с образцом специального входного файла, сформированного из выходных данных, seq 21
чтобы продемонстрировать, что он работает.
Использование 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
$
Это решение позволяет вам передавать "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, поэтому он подходит для вашего конвейера.
+N
шаблон является расширением GNU. Измените первыйn
наN
второй во втором примере, чтобы он включал линию с узором.