sed中的环境变量替换


202

如果我从脚本运行以下命令:

#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' 

我在教程中读到,要从shell替换环境变量,您需要停止操作,并对部分进行“引用”,$varname以便不直接替换该部分,这是我所做的,并且仅当该变量在紧接之前定义时才起作用。

我如何被s识别$var为shell中定义的环境变量?


4
$ PWD包含一个/,以结束替代命令。
derobert

@德罗伯特:tnx。解决方案之一解决了这个问题
RomanM

4
set -x在shell中使用可使shell在执行每个命令之前回显每个命令。这可以消除很多混乱。(此外,我经常set -u使取消引用未设置的变量成为一个硬错误。(另请参见set -e。))
bobbogo 2012年

我希望找到sed处理环境变量的方法,以免将值泄漏到进程表中,似乎sed是根据此线程中所有答案安装机密的错误工具
ThorSummoner19年

Answers:


302

您的两个示例看起来相同,这使问题难以诊断。潜在问题:

  1. 您可能需要双引号,例如 sed 's/xxx/'"$PWD"'/'

  2. $PWD可能包含一个斜杠,在这种情况下,您需要查找一个包含在其中的字符$PWD用作定界符。

同时解决这两个问题

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

但是,我可以确定使用哪个字符确定不会出现在路径名中?
RomanM

5
您可以有多个候选人,例如@#%!并检查一个case表达式以查找$ PWD是否包含它们。例如,@的情况“ $ PWD” ;*)delim =“ @” ;; esac; 重复执行,直到$ delim不为空。
诺曼·拉姆齐

还有另一种替代方法,而不是使用双引号。请参阅下面的答案
Thales Ceolin 2014年

您可以对sed使用另一个定界符。如果您的环境变量是url,则无需使用/也可以使用。
Guchelkaben

123

除了Norman Ramsey的答案外,我还要补充一点,您可以对整个字符串加双引号(这可以使该语句更具可读性且不易出错)。

因此,如果要搜索'foo'并将其替换为$ BAR的内容,可以将sed命令括在双引号中。

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

在第一个$ BAR将无法正确扩展,而在第二个$ BAR将正确扩展。


4
这是清洁比双引号,单引号等搞乱
Vladislavs Dovgalecs

这是我必须用来获取环境变量以在此命令中正确扩展的功能:sed -i“ s / 127.0.0.1 / 127.0.0.1 localhost $ HOSTNAME /”主机
izikandrw

2
这很简洁,但是当您想进行一些更复杂的替换(例如"2,$s/^/$foo/"$s被解释为变量,但不应替换)时,它将无法正常工作。
mjp

59

您可以使用“ /”以外的其他字符代替:

sed "s#$1#$2#g" -i FILE

在我的特定情况下,$ 2是文件路径,sed由于解释了/$ 2的内容,所以也进行了倒入。这正是我克服它所需要的。谢谢你的小费!
Boyd Hemphill

54

另一个简单的选择:

由于$PWD通常将包含一个斜杠/,因此对sed语句使用|代替/

sed -e "s|xxx|$PWD|"

4
您说过“使用双引号的替代方法”,但是您的示例使用双引号吗?
Jeach 2014年

我想关键是它不直接在$PWD... 周围使用双引号?
基督教徒

14

通过您的问题编辑,我看到了您的问题。假设当前目录为/home/yourname ...,在这种情况下,您的命令如下:

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

将扩展到

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

这是无效的。如果要执行此操作,则需要在$ PWD中\的每个字符前面放置一个字符/


但是PWD是由外壳定义的...如果我回显$ PWD
则会

1
那么,如何逃避环境变量?
einpoklum 2014年

1
所选答案描述了一种解决方法...不要在定界符中使用斜线
Eddie

一旦您的当前工​​作目录包含其他字符,这将成为问题。
blubberdiblub

6

坏方法:更改定界符

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

也许那些不是最终答案,

你可以不知道会发生什么性质的$PWD/ :@

好的方法是替换中的特殊字符$PWD

好方法:转义分隔符

例如:尝试替换URL为$ url(已包含: /内容)

x.com:80/aa/bb/aa.js

在字符串$ tmp中

<a href="URL">URL</a>

一个。使用/作为分隔符

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>

要么

b。使用:作为分隔符(除了更易读/

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>

3

实际上,最简单的方法(至少在gnu sed中)是对sed替换命令使用不同的分隔符。因此,与其将s / pattern /'$ mypath'/扩展为s / pattern // my / path /当然会混淆s命令,请使用s!pattern!'$ mypath'!它将扩展为s!pattern!/ my / path!我使用了bang(!)字符(或使用任何您喜欢的字符)来避免使用通常的,但不意味着您只能选择的正斜杠作为分隔符。


3
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1' 

其中VAR包含您要替换为的字段


3

在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

我正在努力使其在Azure DevOps YAML管道中工作。此注释帮助我成功使用此技巧来标记一些配置文件。
andov

1

我有类似的问题,我有一个列表,我必须基于模板(包含@INPUT@在要替换的元素中)构建一个SQL脚本:

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.