将变量传递给 sed 时出现问题

将变量传递给 sed 时出现问题

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

sed '894!d' cloud.cpp

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

lnum=894
sed "$lnum!d" cloud.cpp

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

sed "894!d" cloud.cpp

那么在这种情况下我怎样才能将变量传递给 sed.

答案1

如果您的变量仅包含数字,则您所做的操作是正确的:

sed "$lnum!d" cloud.cpp

对于sed一般情况下传递 shell 变量,请阅读这个答案


现在,在这种情况下你已经正确地完成了它,但它仍然不起作用。这是由于你的外壳,这可能是bashzsh或者csh。这些 shell 支持历史扩展,用!(此功能最初来自csh和 ,后来复制为bash)表示zsh

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

zsh

$ seq 10 | sed "10!d" # <-- press enter
$ seq 10 | sed "10dash"

dash是我历史上最新的命令,以 开头d

bash

$ seq 10 | sed "10!d"
bash: !d": event not found

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

您可以关闭历史扩展:

set +H

或者:

set +o histexpand

bash和:

set -K

或者:

setopt nohistexpand

zsh


对于更便携的方式,在不依赖 shell 选项的情况下,您始终可以执行以下操作:

sed "$lnum"\!d cloud.cpp

这会导致你的外壳!按字面意思对待。

答案2

正如您所提到的,您必须使用双引号,因为当您对字符串使用单引号时,其内容将按字面意思处理。但就你而言,你有模式和变量的组合。因此,您应该对模式使用单引号,对变量使用双引号:

sed "$lnum"'!d' cloud.cpp

答案3

您没有提到您正在使用哪种外壳。下面的答案假设它是bash.


您正在 shell 中触发历史扩展。从man bash

!string

引用历史列表中以字符串开头的当前位置之前的最新命令。

奇怪的是:

如果启用,将执行历史扩展,除非!使用反斜杠转义出现在双引号中的内容。前面的反斜杠! 不会被删除。

因此我认为单独引用它们可能是最好的解决方案:

sed "$lnum"'!d' cloud.cpp

这也有效(为您节省一个字符):

sed "$lnum"\!d cloud.cpp

这也有效(如果您喜欢双引号):

sed "$lnum""!""d" cloud.cpp

相关内容