Подстановка переменной среды в sed
Если я запускаю эти команды из скрипта:
#my.sh
PWD=bla
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
xxx
bla
это нормально.
Но если я бегу:
#my.sh
sed 's/xxx/'$PWD'/'
...
$ ./my.sh
$ sed: -e expression #1, char 8: Unknown option to `s'
Я прочитал в уроках, что для замены переменных окружения из оболочки вам нужно остановиться, и "из кавычек" $varname
часть, так что она не подставляется напрямую, что я и сделал, и которая работает, только если переменная определена непосредственно перед этим.
Как я могу успокоиться, чтобы распознать $var
как переменная окружения, как это определено в оболочке?
12 ответов
Ваши два примера выглядят одинаково, что затрудняет диагностику проблем. Потенциальные проблемы:
Вам могут понадобиться двойные кавычки, как в
sed 's/xxx/'"$PWD"'/'
$PWD
может содержать косую черту, в этом случае вам нужно найти символ, не содержащийся в$PWD
использовать в качестве разделителя.
Возможно, чтобы решить обе проблемы одновременно
sed 's@xxx@'"$PWD"'@'
В дополнение к ответу Нормана Рэмси я хотел бы добавить, что вы можете заключить в кавычки всю строку (что может сделать оператор более читабельным и менее подверженным ошибкам).
Так что если вы хотите найти 'foo' и заменить его содержимым $BAR, вы можете заключить команду sed в двойные кавычки.
sed 's/foo/$BAR/g'
sed "s/foo/$BAR/g"
В первом случае $ BAR не будет правильно расширяться, а во втором $ BAR будет расширяться правильно.
Еще одна простая альтернатива:
поскольку $PWD
обычно будет содержать косую черту /
использовать |
вместо /
для заявления sed:
sed -e "s|xxx|$PWD|"
Вы можете использовать другие символы, кроме "/", в подстановке:
sed "s#$1#$2#g" -i FILE
плохой способ: изменить разделитель
sed 's/xxx/'"$PWD"'/'
sed 's:xxx:'"$PWD"':'
sed 's@xxx@'"$PWD"'@'
может быть, это не окончательный ответ,
Вы не можете знать, какой персонаж появится в $PWD
, /
:
ИЛИ ЖЕ @
,
хороший способ - заменить специальный символ в $PWD
,
хороший способ: экранирующий символ
например:
использование /
в качестве разделителя
echo ${url//\//\\/}
x.com:80\/aa\/bb\/aa.js
echo ${url//\//\/}
x.com:80/aa/bb/aa.js
echo "${url//\//\/}"
x.com:80\/aa\/bb\/aa.js
echo $tmp | sed "s/URL/${url//\//\\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>
echo $tmp | sed "s/URL/${url//\//\/}/"
<a href="x.com:80/aa/bb/aa.js">URL</a>
ИЛИ ЖЕ
использование :
как разделитель (более читаемый, чем /
)
echo ${url//:/\:}
x.com:80/aa/bb/aa.js
echo "${url//:/\:}"
x.com\:80/aa/bb/aa.js
echo $tmp | sed "s:URL:${url//:/\:}:g"
<a href="x.com:80/aa/bb/aa.js">x.com:80/aa/bb/aa.js</a>
С редактированием вашего вопроса я вижу вашу проблему. Допустим, текущий каталог /home/yourname
... в этом случае ваша команда ниже:
sed 's/xxx/'$PWD'/'
будет расширен до
sed `s/xxx//home/yourname//
который не действителен. Вам нужно положить \
персонаж перед каждым /
в вашем $PWD, если вы хотите сделать это.
На самом деле, самая простая вещь (по крайней мере в gnu sed) - это использовать другой разделитель для команды sed substitution (s). Поэтому вместо того, чтобы s / pattern / '$mypath' / была расширена до s / pattern // my / path /, что, конечно, запутает команду s, используйте s! Pattern! '$ Mypath'! который будет расширен до s! pattern! / my / path! Я использовал символ взрыва (!) (Или используйте все, что вам нравится), который избегает обычной косой черты, но не означает, что ваш выбор только как разделитель.
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1'
где VAR содержит то, что вы хотите заменить поле
Работа с переменными внутри sed
[root@gislab00207 ldom]# echo domainname: None > /tmp/1.txt
[root@gislab00207 ldom]# cat /tmp/1.txt
domainname: None
[root@gislab00207 ldom]# echo ${DOMAIN_NAME}
dcsw-79-98vm.us.oracle.com
[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: ${DOMAIN_NAME}/g'
--- Below is the result -- very funny.
domainname: ${DOMAIN_NAME}
--- You need to single quote your variable like this ...
[root@gislab00207 ldom]# cat /tmp/1.txt | sed -e 's/domainname: None/domainname: '${DOMAIN_NAME}'/g'
--- The right result is below
domainname: dcsw-79-98vm.us.oracle.com
Если ваша строка замены может содержать другие управляющие символы sed , то вам может понадобиться двухэтапная замена (сначала экранирование строки замены ):
PWD='/a\1&b$_' # these are problematic for sed
PWD_ESC=$(printf '%s\n' "$PWD" | sed -e 's/[\/&]/\\&/g')
echo 'xxx' | sed "s/xxx/$PWD_ESC/" # now this works as expected
У меня была похожая проблема, у меня был список, и я должен построить сценарий SQL на основе шаблона (который содержал @INPUT@
как элемент для замены):
for i in LIST
do
awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
для меня замена некоторого текста на значение переменной среды в файле с sed работает только с квотой следующим образом:
sed -i 's/original_value/'"$MY_ENVIRNONMENT_VARIABLE"'/g' myfile.txt
НО, когда значение MY_ENVIRONMENT_VARIABLE содержит URL-адрес (т. е. https://andreas.gr), то вышеуказанное не работает. ТОГДА используйте другой разделитель:
sed -i "s|original_value|$MY_ENVIRNONMENT_VARIABLE|g" myfile.txt