将变量传递给 sed 的问题

pho*_*les 5 shell sed quoting

我知道在将变量传递给 sed 时,应该使用双引号。因此,当我使用 sed 显示给定行号的文件行时:

sed '894!d' cloud.cpp
Run Code Online (Sandbox Code Playgroud)

它有效,但由于我也想将行号 894 作为变量传递给 sed,所以我尝试了:

lnum=894
sed "$lnum!d" cloud.cpp
Run Code Online (Sandbox Code Playgroud)

但它不起作用,甚至具有相同语法的单引号也不起作用:

sed "894!d" cloud.cpp
Run Code Online (Sandbox Code Playgroud)

所以在这种情况下,我如何仍然将变量传递给 sed。

cuo*_*glm 9

如果您的变量只包含数字,那么您所做的就是正确的:

sed "$lnum!d" cloud.cpp
Run Code Online (Sandbox Code Playgroud)

要将 shell 变量传递给sed一般,请阅读此答案


现在,在这种情况下,您已正确完成此操作,但仍然无法正常工作。这归因于您的外壳,这可能是bash,zshcsh. 这些shell支持历史扩展,用!(这个特性是原始的csh,后来被bash和复制的zsh)表示。

bash, 中zsh,交互式会话中默认启用历史扩展,并将在双引号内执行。

zsh

$ seq 10 | sed "10!d" # <-- press enter
$ seq 10 | sed "10dash"
Run Code Online (Sandbox Code Playgroud)

就像dash我历史上的最新命令一样,以d.

bash

$ seq 10 | sed "10!d"
bash: !d": event not found
Run Code Online (Sandbox Code Playgroud)

因为我在 bash 历史记录中没有任何命令以d.

您可以关闭历史扩展:

set +H
Run Code Online (Sandbox Code Playgroud)

或者:

set +o histexpand
Run Code Online (Sandbox Code Playgroud)

bash和:

set -K
Run Code Online (Sandbox Code Playgroud)

或者:

setopt nohistexpand
Run Code Online (Sandbox Code Playgroud)

zsh


对于更便携的方式,不依赖于你的 shell 选项,你总是可以这样做:

sed "$lnum"\!d cloud.cpp
Run Code Online (Sandbox Code Playgroud)

这会导致您的外壳按!字面意思处理。


Dab*_*abi 7

正如您所提到的,您必须使用双引号,因为当您对字符串使用单引号时,其内容将按字面处理。但是在您的情况下,您有模式和变量的组合。所以你应该对模式使用单引号,对变量使用双引号:

sed "$lnum"'!d' cloud.cpp
Run Code Online (Sandbox Code Playgroud)

  • 这在`(t)csh` shell 中是行不通的,也没有说明幕后真正的问题。 (2认同)