Использование sed в скрипте оболочки с многострочными переменными

Использование sed в скрипте оболочки с многострочными переменными

Я использую скрипты оболочки для настройки различных типов виртуальных машин. Часто эти скрипты включают многострочные переменные, которые необходимо вставить в файлы конфигурации в определенных позициях с помощью sed.

Если я создам их вот так, то все будет хорошо:

VAR="Config Line1\nConfig Line2\nConfig Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

Однако это не делает сценарий очень читабельным, особенно с учетом того, что текстовые блоки могут быть довольно длинными.

Если я напишу их так:

VAR="Config Line1
Config Line2
Config Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

При запуске скрипта возникает ошибка: sed: -e expression #1, char 31: unknown command:C'`

Есть ли способ использовать sedпеременные, объявленные таким образом?

решение1

Стандартный синтаксис команды a:

sed -e 'a\
first line\
  second line\
last line'

BSD (по крайней мере FreeBSD и OS/X) sedудаляет начальные пробелы, инужно -eобойти ошибку. GNU sedпозволяет переместить первую строку сразу после , a\если она не пустая.

Итак, вам необходимо предварительно обработать входные данные:

VAR='content with
multiple lines
  some with lead blanks
or even backslash\'

preprocessed_VAR=$(printf '%s\n' "$VAR" |
  sed 's/\\/&&/g;s/^[[:blank:]]/\\&/;s/$/\\/')

sed -i -e "/MatchingPattern/a\\
${preprocessed_VAR%?}" somefile

(замените -iна -i ''во FreeBSD или OS/X).

В GNU/Linux и с оболочкой GNU ( bash) или zshвместо этого вы можете сделать следующее:

sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"

Это работает, потому что bashи zshреализуются строки here с удаленными временными файлами, а /dev/stdin в Linux реализован как символическая ссылка на файл (что означает, что его можно открывать несколько раз, и каждый раз он будет открываться в начале).

Здесь вы также можете использовать GNU awk:

(export VAR
gawk -i /usr/share/awk/inplace.awk '{print}; /MatchingPattern/{print ENVIRON["VAR"]}' somefile)

Не использовать-i inplaceas сначала gawkпытается загрузить inplaceрасширение (как inplaceили inplace.awk) из текущего рабочего каталога, где кто-то мог разместить вредоносное ПО. Путь расширения, inplaceпоставляемого с, gawkможет различаться в зависимости от системы, см. выводgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

Или perl(откуда это -i):

(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)

решение2

Ошибка возникает из-за того, что sedкоманде append aтребуется обратная косая черта после фактического a:

С GNU sed:

$ sed "/pattern/a\\$VAR" file.in >file.out

sedНасколько мне известно, BSD может вставлять в файл с помощью этой aкоманды только одну строку, если только символы новой строки не экранированы должным образом.

Близкий ответ о том, как решить эту проблему с помощью BSD sed:http://unix.stackexchange.com/a/60322

Связанный контент