如果我从脚本运行这些命令:
#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
部分,以便它不会被直接替换,这就是我所做的,并且只有在立即定义变量时才有效前。
如何让 sed 将 $var
识别为环境变量,因为它在 shell 中定义?
set -x
让 shell 在执行每个命令之前回显它们。这可以消除很多混乱。 (另外,我经常使用 set -u
使取消引用未设置的变量成为一个硬错误。(也请参见 set -e
。))
您的两个示例看起来相同,这使得问题难以诊断。潜在问题:
您可能需要双引号,如 sed 's/xxx/'"$PWD"'/' $PWD 可能包含斜杠,在这种情况下,您需要找到 $PWD 中未包含的字符用作分隔符。
要同时解决这两个问题,也许
sed 's@xxx@'"$PWD"'@'
除了 Norman Ramsey 的回答之外,我还想补充一点,您可以用双引号括起整个字符串(这可能会使语句更具可读性且不易出错)。
因此,如果要搜索 'foo' 并将其替换为 $BAR 的内容,可以将 sed 命令括在双引号中。
sed 's/foo/$BAR/g'
sed "s/foo/$BAR/g"
在第一个中,$BAR 将无法正确扩展,而在第二个中,$BAR 将正确扩展。
"2,$s/^/$foo/"
因为 $s
也被解释为变量,它不应该。
"2,$ s/^/$foo/"
另一个简单的选择:
由于 $PWD
通常包含斜杠 /
,因此 sed 语句使用 |
而不是 /
:
sed -e "s|xxx|$PWD|"
$PWD
周围使用双引号......?
您可以使用“/”以外的其他字符进行替换:
sed "s#$1#$2#g" -i FILE
sed
由于解释了 $2 内容中的 /
而引起了轰动。这正是我需要克服的。感谢一个伟大的提示!
一.坏方法:更改分隔符
sed 's/xxx/'"$PWD"'/'
sed 's:xxx:'"$PWD"':'
sed 's@xxx@'"$PWD"'@'
也许那些不是最终的答案,
您无法知道 $PWD
、/
:
或 @
中会出现什么字符。
如果 $PWD 中的分隔符字符,它们会破坏表达式
好的方法是替换(转义)$PWD
中的特殊字符。
二.好方法:转义分隔符
例如:尝试将 URL
替换为 $url(内容中有 :
/
)
x.com:80/aa/bb/aa.js
在字符串 $tmp
<a href="URL">URL</a>
A. 使用 / 作为分隔符
在 var 中将 /
转义为 \/
(在 sed 表达式中使用之前)
## step 1: try escape
echo ${url//\//\\/}
x.com:80\/aa\/bb\/aa.js #escape fine
echo ${url//\//\/}
x.com:80/aa/bb/aa.js #escape not success
echo "${url//\//\/}"
x.com:80\/aa\/bb\/aa.js #escape fine, notice `"`
## step 2: do sed
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. 使用 : 作为分隔符(比 / 更具可读性)
在 var 中将 :
转义为 \:
(在 sed 表达式中使用之前)
## step 1: try escape
echo ${url//:/\:}
x.com:80/aa/bb/aa.js #escape not success
echo "${url//:/\:}"
x.com\:80/aa/bb/aa.js #escape fine, notice `"`
## step 2: do sed
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 替换 (s
) 命令使用不同的分隔符。因此,不要将 s/pattern/'$mypath'/
扩展为 s/pattern//my/path/
,这当然会混淆 s
命令,而是使用 s!pattern!'$mypath'!
,它将扩展为 s!pattern!/my/path!
。我使用了 bang (!
) 字符(或使用任何你喜欢的字符),它避免了通常的,但绝不意味着你唯一选择的正斜杠作为分隔符。
在 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
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1'
其中 VAR
包含您要替换该字段的内容
我有类似的问题,我有一个列表,我必须基于模板构建一个 SQL 脚本(包含 @INPUT@
作为要替换的元素):
for i in LIST
do
awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
如果您的替换字符串可能包含其他 sed control characters,那么您可能需要两步替换(第一个 escaping the replacement string):
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
不定期副业成功案例分享