我知道将变量传递给 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 变量,请阅读这个答案。
现在,在这种情况下你已经正确地完成了它,但它仍然不起作用。这是由于你的外壳,这可能是bash
,zsh
或者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