Удалите диапазон строк выше шаблона с sed (или awk)

Ваш sshd сервер, слушающий на порте 22, попытайтесь добавить:

Port 22

к Вашей конфигурации.

Если это не работает попытка, передавая порт выше 1024 (Некоторый ISP не позволяют не бизнес-абонентский трафик на портах ниже 1024). Также удостоверьтесь, делаете ли Вы это, Вы изменяете строку в conf, который я просто сказал Вам собирающийся отразить то же значение.

29
15.12.2015, 03:24
5 ответов

Sed не отслеживает в обратном порядке: после того как это обработало строку, это сделано. Так “находят строку и печатают предыдущие строки N”, не собирается работать, как, в отличие от этого, “находят строку и печатают следующие строки N”, на котором легко привить.

Если файл не является слишком длинным, так как Вы, кажется, соглашаетесь с расширениями GNU, можно использовать tac инвертировать строки файла.

tac | sed '/banana/I,+2 d' | tac

Другой угол атаки состоит в том, чтобы поддержать раздвижное окно в инструменте как awk. Адаптация от Является там какой-либо альтернативой-A grep-B-C переключатели (для печати немногих строк прежде и после)? (предупреждение: минимально протестированный):

#!/bin/sh
{ "exec" "awk" "-f" "$0" "$@"; } # -*-awk-*-
# The array h contains the history of lines that are eligible for being "before" lines.
# The variable skip contains the number of lines to skip.
skip { --skip }
match($0, pattern) { skip = before + after }
NR > before && !skip { print NR h[NR-before] }
{ delete h[NR-before]; h[NR] = $0 }
END { if (!skip) {for (i=NR-before+1; i<=NR; i++) print h[i]} }

Использование: /path/to/script -v pattern='banana' -v before=2

22
27.01.2020, 19:38
  • 1
    sed может сделать раздвижные окна также, но получающийся сценарий обычно так нечитабелен, что легче просто использовать awk. –  jw013 24.01.2012, 22:30
  • 2
    @Gilles.. awk сценарий является не совсем правильным; как есть это печатает пустые строки и пропускает последние строки. Это, кажется, фиксирует его, но это не может быть идеально или правильно само: if (NR-before in h) { print...; delete...; } ... и в END раздел: for (i in h) print h[i] ... Кроме того, awk сценарий печатает согласующий отрезок длинной линии, но tac/sec версия не делает; но вопрос немного неоднозначен на этом.. "Исходный" awk сценарий, которому Вы предоставили ссылку, хорошо работает.. Мне нравится он... Я не уверен, как вышеупомянутая 'модификация' влияет на печать после строк... –  Peter.O 25.01.2012, 16:56
  • 3
    @Peter. O Спасибо, awk сценарий должен быть лучше теперь. И мне потребовались меньше чем 6-8 лет! –  Gilles 'SO- stop being evil' 15.12.2015, 03:24

Используя "раздвижное окно" в perl:

perl -ne 'push @lines, $_;
          splice @lines, 0, 3 if /banana/;
          print shift @lines if @lines > 2
          }{ print @lines;'
7
27.01.2020, 19:38

Используя man 1 ed:

str='
1
2
3
banana
4
5
6
banana
8
9
10
'

# using Bash
cat <<-'EOF' | ed -s <(echo "$str")  | sed -e '1{/^$/d;}' -e '2{/^$/d;}'
H
0i


.
,g/banana/km\
'm-2,'md
,p
q
EOF
1
27.01.2020, 19:38

Вы можете сделать это довольно просто с помощью sed :

printf %s\\n    1 2 3 4match 5match 6 \
                7match 8 9 10 11match |
sed -e'1N;$!N;/\n.*match/!P;D'

Я не знаю, почему кто-то сказал в противном случае, но для найти строку и распечатать предыдущие строки sed включает встроенный примитив rint P , который записывает только до первого \ n символ ewline в пространстве образца.Дополнительный примитив D elete удаляет тот же самый сегмент пространства шаблонов, прежде чем рекурсивно перезапустить сценарий с тем, что осталось. И в завершение, есть примитив для добавления строки ввода N ext в пространство шаблона после вставленного символа \ n ewline.

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

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


1
7match
8
11match

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

Итак:

    printf %s\\n     1 2 3 4 5 6 7match     \
                     8match 9match 10match  \
                     11match 12 13 14 15 16 \
                     17 18 19 20match       |
    sed -e:b -e'$!{N;2,5bb' -e\} -e'/\n.*match/!P;D'

1
11match
12
13
14
20match

... удаляет 5 строк, предшествующих любому совпадению.

6
27.01.2020, 19:38

Это довольно просто с помощью ex или vim -e

    vim -e - $file <<@@@
g/banana/.-2,.d
wq
@@@

. Выражение гласит: для каждой строки, содержащей банан в диапазоне от текущей строки -2 до текущей строки, удалите.

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

    vim -e - $file <<@@@
g/banana/?apple?,/orange/d
wq
@@@
19
27.01.2020, 19:38

Теги

Похожие вопросы