![在 sed 中使用对 bash 字符串变量的引用](https://linux22.com/image/45664/%E5%9C%A8%20sed%20%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%AF%B9%20bash%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8F%98%E9%87%8F%E7%9A%84%E5%BC%95%E7%94%A8.png)
我是一个相对的Linux新手。假设我有一个a.txt
包含以下文本的文本文件:
A
B
C
现在,如果我想更改第 2 行(包含 )上的文本B
,我可以使用以下sed
命令:
sed -i '2s/^.*$/X/' a.txt
例如,将 更改B
为。X
但现在假设我想编写一个sed
命令,将第 2 行的文本更改为包括bash 字符串变量。我想将第 2 行的文本更改为fname="myaddress"
,其中明确包含引号,并且其中myaddress
是bash 字符串变量(在其他地方定义)。为了尝试做到这一点,我创建了一个名为mytest.sh
并包含以下内容的 bash shell 脚本:
#!/bin/bash
myaddress="/home/"
echo fname=\"$myaddress\"
head a.txt
sed -i '2s/^.*$/fname=\"$myaddress\"/' a.txt
head a.txt
现在,echo fname=\"$myaddress\"
打印fname="/home/"
,这是我的文本想位于 的 2 号线a.txt
。但是,sed
而是打印fname="$myaddress"
到 的第 2 行a.txt
,可能是因为它位于周围的撇号内。换句话说,上面的 bash shell 脚本的输出是:
fname="/home/"
A
B
C
A
fname="$myaddress"
C
我的问题是,我怎样才能sed
真正打印价值存储在? 中myaddress
并由$myaddress
?引用
答案1
s
如果您希望无论变量的内容是什么,替换都可以工作,则必须对变量中命令右侧特殊的字符进行转义,sed
其中包括:
- 分隔符本身(上面,您使用了
/
) &
被匹配的字符串替换- 需要转义的换行符
\
它用于逃避上述所有内容并介绍\1
,\2
...
喜欢:
escaped_var=$(printf '%s\n' "$var" | sed 's:[/&\]:\\&:g;s/$/\\/')
escaped_var=${escaped_var%?}
sed "s/regexp/$escaped_var/g"
由于这相当麻烦,您可能想使用perl
:
v=$var perl -pe 's/regexp/$ENV{v}/g'
sed
的等价物2s
是:
v=$var perl -pe 's/regexp/$ENV{v}/g if $. == 2'
当然,在你的情况下,你宁愿这样写:
v=$myaddress perl -pe '$_ = "fname=\"$ENV{v}\"\n" if $. == 2'
另一个优点是它也可以处理二进制数据,并且您可以使用一个-i
选项进行就地编辑,而使用 时sed
,您只能在sed
GNU 的系统上执行此操作sed
。
另请注意,NUL 字符不能存储在环境变量中。
答案2
shell 不解释单引号内的变量。您需要将它们更改为双引号。由于您的变量中有斜杠,因此您应该使用不同的分隔符:
sed -i "2s|^.*\$|fname=\"$myaddress\"|" a.txt
请注意,我转义了行尾$
,因此 shell 不会解释它。在这种情况下不会,但您应该养成转义$
要保留在双引号中的 s 的习惯。您还可以使用几对引号来做到这一点:
sed -i '2s|^.*$|fname="'"$myaddress"'"|' a.txt
答案3
有两个问题:首先,正如 Kevin 已经指出的,如果要由 shell 扩展 shell 变量,则需要将它们括在双引号中。其次,您的替换字符串包含/
,因此您不能/
同时用作 的分隔符sed
。如果您知道某些字符(例如,
)肯定不会出现在替换字符串中,则可以使用该字符作为sed
分隔符,这样您就得到
sed -i '2s,^.*$,fname="'"$myaddress"'",' a.txt