Как с помощью sed заменить шаблон, если он встречается в строке, следующей за другим шаблоном?

Добавьте BEGIN { OFS="\t" } в начало сценария awk и измените {print } на {print $1, $2, $3, $4}. Это изменит разделитель полей вывода awk на tab с пробела по умолчанию.

EDIT:

Для n столбцов можно использовать {$1 = $1; print} вместо {print}. Я не уверен, как это работает внутри, но при тестировании это работает.

4
24.07.2017, 15:44
3 ответа

Компактнее и легче:

sed 'G;/^Value=/s/=.*\nName=Tom/=42/;s/\n.*//;h' file

Это добавляет к каждой строке предыдущую строку из пробела. Для строк Value=значение заменяется, если Name=Tomбыло в ячейке удержания. В противном случае добавленная строка удаляется, а строка сохраняется в резервном пространстве для следующего цикла.

4
27.01.2020, 20:46

сawk:

awk 'prev ~ /^Name=(Tom|Anything)$/ && /^Value=/ {$0 = "Value=123"}
     {print; prev = $0}'

Или с именем и новым значением , сохраненным в переменной:

export NAME=Tom VALUE=123
awk 'prev == "Name=" ENVIRON["NAME"] && /^Value=/ {
       $0 = "Value=" ENVIRON["VALUE"]
     }
     {print; prev = $0}'

Для sedэквивалентом будет что-то вроде:

sed -e 'x;/^Name=Tom$/{g;/^Value/s/=.*/=123/;h;b' -e '}' -e g

Хотя, как обычно, он короче, но значительно менее разборчив, чем с awk. Кроме того, для работы с произвольными значениями, хранящимися в переменных, sedне имеет эквивалента awkENVIRONили возможности простого сравнения строк (в отличие от сопоставления регулярных выражений ). поэтому вам нужно предварительно -обработать значения переменных, если только вы не можете гарантировать, что переменные не содержат специальных символов для sed.

sed -e "x;/^Name=$NAME\$/{g;/^Value/s/=.*/=$VALUE/;h;b" -e '}' -e g

Может быть уязвимость, связанная с внедрением команд (, по крайней мере, с GNU sed), если $NAMEи $VALUEне контролируются жестко.

5
27.01.2020, 20:46
sed -e '
   /^Name=Tom$/!b
   $!N
   /\(\nValue\)=.*/s//\1=NEW_VALUE/
   P;D
' data.inp

Пояснение

  • Он будет искать строки, в которых есть имя Том. Несоответствие -будет отправлено на стандартный вывод.
  • Затем он попытается добавить следующую строку в пространство шаблона, если это не последняя строка.
  • Будет искать регулярное выражение Value= в только что добавленной строке, и если да, то значение изменится на NEW _VALUE (вы должны изменить его на то, что вам нужно ).
  • P;D => напечатает часть пространства шаблона слева от \n, т. е. предыдущую строку, в которой было Name=Tom, а затем удалит эту часть. Теперь у нас осталось Value=NEW _VALUE, и с этим происходит переход к началу строки сценария sed :/^Name=Tom$/!b стандартный выход. Это сделано, чтобы позаботиться о последовательных строках Name=Tom.

Результаты

Name=Tom
Value=NEW_VALUE
Name=Tom
Name=Harry
Value=20
4
27.01.2020, 20:46

Теги

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