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

Скажем, следующее является содержимым файла

$ cat file Name=Tom Value=10 Name=Tom Name=Harry Value=20 

В некоторых случаях значение не возникает после имени. Поэтому мне нужно найти шаблон Name = Tom и заменить значение, но только если оно встречается в строке сразу после имени. Как это сделать?

3 Solutions collect form web for “Использовать sed, как заменить шаблон, если он встречается в строке, следующей за другим шаблоном?”

Более компактный и несколько более простой:

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

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

с 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 '}' -eg 

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

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

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

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

объяснение

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

Результаты

 Name=Tom Value=NEW_VALUE Name=Tom Name=Harry Value=20 
  • SED: удалить 4 строки выше и ниже 5 строк после соответствия шаблону
  • (Mac Terminal) sed для анализа JSON ... что я делаю неправильно?
  • Поиск и замена имени пути в Linux с помощью sed
  • Извлечение текстовых блоков на основе вывода grep
  • Почему sed не выходит сразу после записи вывода?
  • Как обмениваться словами в имени файла с помощью оболочки?
  • Regex: нужна помощь с использованием awk и sed для соответствия веб-сайтам по IP-адресу
  • вставить новую строку, когда отрицательный + положительный шаблон найден с помощью sed
  • Как я могу передать $ 1 в sed?
  • Удалить запятую между кавычками только в файле с разделителями-запятыми
  • Вставьте строку после блока текста с помощью sed
  • Linux и Unix - лучшая ОС в мире.