Использование Sed для расширения переменных среды внутри файлов - PullRequest
4 голосов
/ 22 октября 2009

Я бы хотел использовать Sed для расширения переменных внутри файла.

Предположим, я экспортировал переменную VARIABLE = что-то, и у меня есть "тестовый" файл со следующим:

I'd like to expand this: "${VARIABLE}"

Я пробовал команды, подобные следующим, но безрезультатно:

cat test | sed -e "s/\(\${[A-Z]*}\)/`eval "echo '\1'"`/" > outputfile

В результате получается «выходной файл» с переменной, которая еще не раскрыта:

I'd like to expand this: "${VARIABLE}"

Тем не менее, выполнение eval "echo '${VARIABLE}' в консоли bash приводит к выводу значения «что-то». Кроме того, я проверил, и этот шаблон полностью соответствует.

Желаемый результат будет

I'd like to expand this: "something"

Может кто-нибудь пролить свет на это?

Ответы [ 2 ]

11 голосов
/ 23 октября 2009

Рассмотрим вашу пробную версию:

cat test | sed -e "s/\(\${[A-Z]*}\)/`eval "echo '\1'"`/" > outputfile

Причина, по которой это не работает, заключается в том, что это требует предвидения со стороны оболочки. Сценарий sed генерируется до того, как sed сопоставит любой шаблон, поэтому оболочка не сможет выполнить эту работу за вас.

Я делал это несколькими способами в прошлом. Обычно у меня был список известных переменных и их значений, и я произвел замену из этого списка:

for var in PATH VARIABLE USERNAME
do
    echo 's%${'"$var"'}%'$(eval echo "\$$var")'%g'
done > sed.script

cat test | sed -f sed.script > outputfile

Если вы хотите отобразить переменные произвольно, то вам нужно либо иметь дело со всей средой (вместо фиксированного списка имен переменных, использовать вывод из env, соответствующим образом отредактированный), либо использовать вместо этого Perl или Python.

Обратите внимание, что если значение переменной среды содержит косую черту в вашей версии, вы столкнетесь с проблемами, используя косую черту в качестве разделителя полей в нотации s ///. Я использовал «%», поскольку его используют относительно немного переменных окружения, но на некоторых машинах есть такие, которые содержат символы «%», поэтому полное решение сложнее. Вам также нужно беспокоиться о обратной косой черте в значении. Вы, вероятно, должны использовать что-то вроде '$(eval echo "\$$var" | sed 's/[\%]/\\&/g')', чтобы избежать обратной косой черты и символов процента в значении переменной среды. Последнее замечание: некоторые версии sed имеют (или имели) ограниченную емкость для размера сценария - более ранние версии HP-UX имели ограничение около 100. Я не уверен, что это все еще проблема, но это было 5 лет назад.

Простая адаптация оригинального сценария гласит:

env |
sed 's/=.*//' |
while read var
do
    echo 's%${'"$var"'}%'$(eval echo "\$$var" | sed 's/[\%]/\\&/g')'%g'
done > sed.script

cat test | sed -f sed.script > outputfile

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

env |
sed 's/[\%]/\\&/g;s/\([^=]*\)=\(.*\)/s%${\1}%\2%/' > sed.script
cat test | sed -f sed.script > outputfile

Это в целом безопаснее, потому что оболочка никогда не оценивает ничего, что не должно оцениваться - вы должны быть очень осторожны с метасимволами оболочки в значениях переменных. Я думаю, что эта версия может столкнуться с какими-либо проблемами, только если какой-то вывод из env искажен.

Осторожно - написание sed сценариев с sed - эзотерическое занятие, но иллюстрирующее силу хороших инструментов.

Все эти примеры не позволяют очистить временные файлы.

6 голосов
/ 23 октября 2009

Может быть, вы можете обойтись без использования sed:

$ echo $VARIABLE
something
$ cat test
I'd like to expand this: ${VARIABLE}
$ eval "echo \"`cat test`\"" > outputfile
$ cat outputfile
I'd like to expand this: something

Пусть переменная оболочки выполняет интерполяцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...