268

如果我从脚本运行这些命令:

#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 将 a 识别$var为环境变量,因为它在 shell 中定义?

4

11 回答 11

398

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

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

  2. $PWD可能包含斜杠,在这种情况下,您需要找到包含在其中的字符$PWD以用作分隔符。

要同时解决这两个问题,也许

sed 's@xxx@'"$PWD"'@'
于 2009-02-25T06:21:34.340 回答
175

除了 Norman Ramsey 的回答之外,我还想补充一点,您可以用双引号括起整个字符串(这可能会使语句更具可读性且不易出错)。

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

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

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

于 2009-04-14T17:24:39.400 回答
77

另一个简单的选择:

因为$PWD通常会包含一个斜杠/,所以使用 sed 语句|来代替:/

sed -e "s|xxx|$PWD|"
于 2014-04-17T13:20:36.823 回答
67

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

sed "s#$1#$2#g" -i FILE
于 2012-03-08T10:37:13.460 回答
18

一. 坏方法:更改分隔符

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>

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>
于 2017-08-24T08:55:56.833 回答
15

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

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

将扩大到

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

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

于 2009-02-25T06:17:36.583 回答
5

实际上,最简单的事情(至少在 GNU sed 中)是对 sed 替换 ( s) 命令使用不同的分隔符。因此,不要s/pattern/'$mypath'/扩展为s/pattern//my/path/,这当然会混淆s 命令,使用s!pattern!'$mypath'!,它将扩展为s!pattern!/my/path!。我使用了 bang ( !) 字符(或使用任何你喜欢的字符),它避免了通常的,但绝不是你唯一选择的正斜杠作为分隔符。

于 2012-01-27T16:25:30.947 回答
4

在 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
于 2013-08-27T19:45:57.483 回答
3
VAR=8675309
echo "abcde:jhdfj$jhbsfiy/.hghi$jh:12345:dgve::" |\
sed 's/:[0-9]*:/:'$VAR':/1' 

whereVAR包含您要替换该字段的内容

于 2013-04-10T07:35:20.477 回答
2

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

for i in LIST 
do
    awk "sub(/\@INPUT\@/,\"${i}\");" template.sql >> output
done
于 2013-03-25T12:58:20.583 回答
0

如果您的替换字符串可能包含其他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
于 2022-01-30T00:35:00.213 回答