Можно ли сопоставить несколько конкретных номеров строк (не диапазонов) с sed?

9

Рассматривать:

echo -e "a\nb\nc\nd\ne\nf\ng\nh" | sed '3,5a test'

Это будет соответствовать линиям 3, 4 и 5.

Но я пытаюсь сопоставить только строки 3 и 5 (не 4). И добавьте «тест» после них.

Водолей Сила
источник

Ответы:

9
echo ... | sed -e '3a test' -e '5a test'

Если операция более сложная, чем в этом случае, вы можете использовать такую ​​структуру:

sed 'b pattern; : action; a \
lalala
b end; : pattern; 3b action; 5b action; : end'

Т.е. вы помещаете все необходимые команды между b pattern;и b end;.

И вы добавляете все ваши шаблоны (номера строк или что-то еще) после : pattern;.

Что происходит, это:

  1. Первая команда перепрыгивает через часть действия (возможно, легче прочитать, если шаблоны находятся в начале и b end;непосредственно перед частью действия).

  2. Если шаблон соответствует, то выполнение переходит к части действия. После выполнения действия часть прыгает до конца.

Я пытаюсь привести в порядок это:

sed '3b action; 5b action; b end; : action; a \
lalala
: end'

В одной строке будет выглядеть так:

sed "3b idAction; 5b idAction; b; : idAction; a test"

Портативно, вам нужно написать это:

sed '
   3b action
   5b action
   b
   : action
   a\
   lalala'

( bбез разветвления метки до конца, поэтому вам не нужна явная endметка, ;в стандартных sedреализациях допустимый символ в метке ).

Хауке Лагинг
источник
4
Ух, седь подпрограммы. Круто
Гленн Джекман
Ничего себе, не могли бы вы остановиться на них? Они выглядят действительно полезными!
Terdon
тот, что с «шаблоном» и «действием», кажется очень хорошим, так как мне не нужно повторять «тест» (или «лалала»), надо еще лучше понять его, хотя! :)
Водолей Power
@terdon Что я мог?
Хауке Лагинг
Я имел в виду, что второй выглядит великолепно, но его трудно понять, и если у вас есть время, я был бы признателен за объяснение.
Terdon
5

С sed(см. Ответ @ HaukeLaging )

С awk:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | awk 'NR==3 || NR==5{$0=$0"\ntest"}1;'

С perl:

$ echo -e "a\nb\nc\nd\ne\nf\ng\nh" | perl -pe '$_ .="test\n" if $. == 3 || $. == 5'
Тердон
источник
Можно немного perl -lnE 'say if $. ~~ @{[3,5]}'
поиграть в свой перл
@glennjackman ах, да, действительно, спасибо. Я должен признать, что немного опасаюсь ~~, не понимаю это так, как следовало бы. Кроме того, оба sayи ~~нужно Perl V> = 5,10 правильно?
Terdon
Мне нужно добавить «тест» после этих строк, теперь я вижу, что было бы лучше уточнить это с самого начала. Я только что отредактировал ОП.
Водолей Power
@AquariusPower, perl -pE 'say "test" if $. ~~ @{[4,6]}'- это добавляет строку: perl's -pнеявно печатает в конце данной программы.
Гленн Джекман
@ AquariusPower также см. Обновленный ответ.
Terdon
3

Как сказал @HaukeLaging aleady, эта команда делает то, что вы хотите:

sed -e'3a test' -e'5a test'

Теперь это может быть довольно громоздким, если вы хотите сопоставить, например, 20 строк.

В этих случаях, если ваша оболочка поддерживает расширение скобок , вы можете использовать эту команду вместо:

sed -e{3,5}'a test'

(Обратите внимание, что фигурные скобки и запятая должны оставаться без кавычек.)

В результате оболочка передаст аргументы -e3a testи -e5a testв sed, что и делает первая команда.

Деннис
источник