使用 sed 将整行替换为 bash 变量

Replace entire line with bash variable using sed

我想使用 sed 来替换与 bash 变量匹配的整行。替换为纯文本即可。

$ echo -e "foo bar\nfooy bary\nfoot bart" | sed '/fooy/c\text'
foo bar
text
foot bart

如果我要替换的文本存储在 bash 变量中,但是,这不起作用。

$ var="This is poetry."
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed "/fooy/c$var"
foo bar
$var
foot bart

我怎样才能做到这一点?

不要转义 $ 符号。在 bash 中,变量由 $variable-name 引用。如果您确实转义了 $ 符号,那么 bash 将不会将其视为变量。它会将 $var 视为文字 $var .

$ echo -e "foo bar\nfooy bary\nfoot bart" | sed "/fooy/c$var"
foo bar
This is poetry.
foot bart

如果你想用 sed 做这个(你不应该这样做,见下文),使用

sed "/fooy/c\$var"

这是一个shell扩展问题。双引号字符串中的 $ 表示字面上的美元,因此 $var 不会展开。 GNU sed 也接受

sed "/fooy/c$var"

只要您不指定 --posix,但 BSD sed(您可能在 FreeBSD 或 MacOS X 上有)会抱怨它。

但是,使用 sed 执行此操作并不是一个好主意。将 shell 变量替换为 sed 代码几乎不是一个好主意,因为它使您容易受到代码注入的攻击。举个例子,

$ var=$(echo -e 'something\nd')
$ echo -e "foo bar\nfooy bary\nfoot bart" | sed --posix "/fooy/c\$var"
something

这不是我们所期望的,是吗?这里发生的是 sed,因为它无法区分您希望将其视为数据($var)和代码的内容,因此将 $var 视为代码,因此它将 d\n 之后作为命令(删除当前行)。更好的方法是使用 awk:

$ var=$(echo -e 'something\nd')
$ echo -e "foo bar\nfooy bary\nfoot bart" | awk -v var="$var" '/fooy/ { print var; next } 1'
foo bar
something
d
foot bart

这通过不将 $var 视为代码来回避代码注入问题。