sed або awk: видаліть n рядків за схемою


105

Як би я змішував шаблони та числові діапазони в sed (або будь-який подібний інструмент - awk, наприклад)? Що я хочу зробити, це відповідати певним рядкам у файлі та видалити наступні n рядків, перш ніж продовжувати, і я хочу це зробити як частину конвеєра.

Відповіді:


187

Я буду ходити в цьому.

Щоб видалити 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: додаткові символи після команда Дякую заздалегідь.
N mol

8
Те, що відбувається схоже, але трохи по-різному у кожному випадку. У першому рецепті /pattern/,+5визначається діапазон, який починається з рядка, що містить "візерунок" ( /pattern/), і закінчується на 5 рядків пізніше ( +5). Останній символ d- це команда для запуску на кожному рядку в тому діапазоні, яка є "видалити". У другому рецепті замість відповідності діапазону він відповідає лише рядку, що містить шаблон ( /pattern/), а потім виконує ряд команд:, {n;N;N;N;N;d}яка в основному друкує наступний рядок (n ), а потім читає і, нарешті, відкидає наступні 4 рядки ( N;N;N;N;d).
pimlottc

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 }ініціалізує кількість пропусків і переходить до наступного рядка, ефективно пропускаючи відповідну лінію; у 2-му розв’язку printпопереднє nextгарантує, що воно є не буде пропущено.
    • --skip >= 0 зменшення кількості пропусків і вживає заходів, якщо це (все-таки)> = 0, маючи на увазі, що поруч слід пропустити лінію.
    • { next } переходить до наступного рядка, фактично пропускаючи поточний рядок
  • 1 - це часто використовувана стенограма для { print } ; тобто поточний рядок просто друкується
    • Тільки невідповідні та пропущені рядки досягають цієї команди.
    • Причина, 1еквівалентна { print }тому, що 1інтерпретується як булева модель, яка за визначенням завжди оцінюється як істина, а це означає, що пов'язана з нею дія (блок) беззастережно виконується. Оскільки в цьому випадку жодної асоційованої дії немає , awkза замовчуванням друкується рядок.

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

10
Нічого собі, це загадково.
pimlottc

3
Розумне (хоч і специфічне для GNU-Sed) рішення, але мало хто отримає користь від нього, якщо ви не додасте пояснення. pattern_number.txt- це файл з двома стовпцями, що містить шаблон, який повинен відповідати в 1-му стовпці, а у 2-му - кількість рядків, які потрібно пропустити. Перша sedкоманда перетворює файл у sedсценарій, який виконує відповідне узгодження та пропуск; цей сценарій надається через -fта stdin ( -) до 2-ї sedкоманди. 2-а 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
$

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 -

Файл з назвою "-" означає stdin для awk, тому це підходить для вашого конвеєра


2
awk здатний бути набагато більш схожим на перл, ніж я зрозумів!
Мартін ДеМелло
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.