Подстановка переменной среды в sed

132

Если я запустил эти команды из script:

#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, чтобы она не была заменена напрямую, что я и сделал, и которая работает только в том случае, если переменная определяется непосредственно перед.

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

  • 3
    $ PWD содержит /, который завершает команду замены.
  • 0
    @derobert: tnx. Одно из решений касается этого ...
Показать ещё 2 комментария
Теги:
sed

10 ответов

211
Лучший ответ

Два примера выглядят одинаково, что затрудняет диагностику проблем. Возможные проблемы:

  • Вам могут потребоваться двойные кавычки, как в sed 's/xxx/'"$PWD"'/'

  • $PWD может содержать косую черту, в этом случае вам нужно найти символ, не содержащийся в $PWD, для использования в качестве разделителя.

Чтобы одновременно прикрыть оба вопроса, возможно,

sed 's@xxx@'"$PWD"'@'
  • 0
    но тогда какой символ я могу использовать, я точно знаю, не появится в пути?
  • 4
    Вы можете иметь несколько кандидатов, таких как @ #%! и проверьте с помощью выражения case, чтобы узнать, есть ли у $ PWD их. Например, регистр "$ PWD" из @ ) ;; *) delim = "@" ;; ESAC; повторяйте, пока $ delim не будет пустым.
Показать ещё 1 комментарий
72

В дополнение к ответу Нормана Рэмси, я бы хотел добавить, что вы можете сдвоить две строки всей строки (что может сделать утверждение более понятным и менее подверженным ошибкам).

Итак, если вы хотите найти "foo" и заменить его содержимым в $BAR, вы можете заключить команду sed в двойные кавычки.

sed 's/foo/$BAR/g'
sed "s/foo/$BAR/g"

В первом случае $BAR не будет правильно расширяться, а во втором $BAR будет правильно расширяться.

  • 4
    Это чище, чем возиться с двойными кавычками, одинарными кавычками и т. Д.
  • 0
    это то, что я должен был использовать для правильного расширения переменной среды в этой команде: sed -i "s / 127.0.0.1 / 127.0.0.1 localhost $ HOSTNAME /" hosts
Показать ещё 1 комментарий
53

Вы можете использовать другие символы, кроме "/", в подстановке:

sed "s#$1#$2#g" -i FILE
  • 0
    В моем конкретном случае $ 2 представлял собой путь к файлу, поэтому sed преувеличивал из-за интерпретации / в содержимом $ 2. Это было именно то, что мне нужно, чтобы пройти через это. Спасибо за отличный совет!
28

Другая простая альтернатива:

Так как $PWD обычно содержит косую черту /, используйте | вместо / для команды sed:

sed -e "s|xxx|$PWD|"
  • 3
    Вы сказали «альтернатива двойным кавычкам», и все же ваш пример использует двойные кавычки?
13

С редактированием вопроса, я вижу вашу проблему. Скажем, текущий каталог /home/yourname... в этом случае ваша команда ниже:

sed 's/xxx/'$PWD'/'

будет расширен до

sed `s/xxx//home/yourname//

что недопустимо. Вам нужно поставить символ \ перед каждым / в вашей $PWD, если вы хотите это сделать.

  • 0
    но PWD определяется оболочкой ... если я пойду echo $ PWD, я получу pwd
  • 1
    Итак, как вы избегаете переменных среды?
Показать ещё 2 комментария
3
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1' 

где VAR содержит то, что вы хотите заменить поле

2

плохой способ: изменить разделитель

sed 's/xxx/'"$PWD"'/'
sed 's:xxx:'"$PWD"':'
sed 's@xxx@'"$PWD"'@'

может быть, это не окончательный ответ,

вы не можете знать, какой будет символ в $PWD, / : OR @.

хороший способ - заменить специальный символ в $PWD.

хороший способ: разделитель escape

например:

использовать / как разделитель

echo ${url//\//\\/}
x.com:80\/aa\/bb\/aa.js

echo ${url//\//\/}
/aa.js

echo "${url//\//\/}"
x.com:80\/aa\/bb\/aa.js

echo $tmp | sed "s/URL/${url//\//\\/}/"
<a href="/aa.js">URL</a>

echo $tmp | sed "s/URL/${url//\//\/}/"
<a href="/aa.js">URL</a>

ИЛИ

использование : как разделитель (более читаемый, чем /)

echo ${url//:/\:}
/aa.js

echo "${url//:/\:}"
x.com\:80/aa/bb/aa.js

echo $tmp | sed "s:URL:${url//:/\:}:g"
<a href="/aa.js">/aa.js</a>
2

На самом деле, самая простая вещь (по крайней мере, в gnu sed) заключается в использовании другого разделителя для команды подстановки sed. Таким образом, вместо s/pattern/'$ mypath//расширяется до s/pattern//my/path/, который, конечно же, путает команду s, используйте s! Pattern!' $Mypath '! который будет расширен до s! pattern!/my/path! Я использовал символ Bang (!) (Или использую все, что вам нравится), что позволяет избежать обычного, но не по-вашему-единственного выбора, косой чертой в качестве разделителя.

1

Работа с VARIABLES внутри 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
1

У меня была аналогичная проблема, у меня был список, и мне нужно создать SQL script на основе шаблона (содержащего @INPUT@ как заменяемый элемент):

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done

Ещё вопросы

Сообщество Overcoder
Наверх
Меню