Pet*_*r.O 15 bash command-history quoting
我意识到这!在命令行历史上下文中对命令行具有特殊意义,但除此之外,在运行脚本中,感叹号有时会导致解析错误。
我认为它与 an 有关event,但我不知道事件是什么或它做什么。即便如此,相同的命令在不同情况下的行为也会有所不同。
下面的最后一个示例导致错误;但是为什么,当相同的代码在命令替换之外工作时呢?.. 使用 GNU bash 4.1.5
# This works, with or without a space between ! and p
{ echo -e "foo\nbar" | sed -nre '/foo/! p'
echo -e "foo\nbar" | sed -nre '/foo/!p'; }
# bar
# bar
# This works, works when there is a space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/! p')"; echo "$var"
# bar
# This causes an ERROR, with NO space between ! and p
var="$(echo -e "foo\nbar" | sed -nre '/foo/!p')"; echo "$var"
# bash: !p': event not found
Run Code Online (Sandbox Code Playgroud)
Cal*_*leb 12
该!字符调用 bash 的历史替换(在交互式 shell 中默认启用)。当后跟一个字符串时(如在您失败的示例中),它会尝试扩展到以该字符串开头的最后一个历史事件。就像$var扩展到该字符串的值一样,!echo将扩展到历史记录中的最后一个 echo 命令。
在这种扩展中,空间是一个破坏性的字符。首先注意这将如何与变量一起工作:
# var="like"
# echo "$var"
like
# echo "$"
$
# echo "Do you $var frogs?"
Do you like frogs? <- as expected, variable name broken at space
# echo "Do you $varfrogs?"
Do you? <- $varfrogs not defined, replaced with blank
# echo "Do you $ var frogs?"
Do you $ var frogs? <- $ not a valid variable name, ignored
Run Code Online (Sandbox Code Playgroud)
历史扩展也会发生同样的事情。bang 字符 ( !) 从历史替换序列开始,但前提是后跟字符串。在它后面加上一个空格使它成为文字爆炸而不是替换序列的一部分。
您可以通过使用单引号来避免这种对变量和历史扩展的替换。您的第一个示例使用单引号,因此运行良好。您的最后一个示例用双引号括起来,因此 bash 在执行任何其他操作之前先扫描它们以查找扩展序列。第一个没有跳闸的唯一原因是空格是一个中断字符,如上所示。
正如Caleb已经说过的,!用于调用 bash 的历史替换。
如果像我一样你觉得你不需要这样的功能,你可以禁用它在中插入以下行~/.bashrc:
set +H
Run Code Online (Sandbox Code Playgroud)
我不需要它,因为历史可以通过向上箭头和Ctrl-r增量反向搜索恢复。有关快捷方式的详细列表,请参阅 bash 的手册页,用于操作历史记录的命令部分。