转义 '!'双引号内

转义 '!'双引号内

bash 手动输入双引号 (https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html) 状态:

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

为什么有一个特殊的案例!?如果我转义 a $(例如),反斜杠不会出现在输出中(例如比较echo "\$"->$echo "\!"-> \!)。

!如果我只想要双引号内的文字该怎么办?

我对这个问题的一个限制是我无法轻松地操纵 bash 调用的形式。我的意思是我坚持使用单个双引号字符串执行命令,即 my-command "a string I generate in an external program that may contain !"

我可以控制字符串的生成方式,但我无法在命令行上将其拆分(例如,类似的东西"part1"\!"part2"对我不起作用。)

答案1

!用is打印字符串不是当不加引号、用单引号引起来、在 C 字符串内或在脚本内时会出现问题。

$ echo hello\!world 'hello!world' $'hello!world'
hello!world hello!world hello!world

$ echo 'echo "hello!world"' >file
$ bash file
hello!world

该脚本示例是一种特殊情况,其中未设置 histexpand(默认情况下)。因此,禁用 histexpand (set +o histexpandshopt -ou histexpand或简单地相同set +H)将具有相同的效果并避免历史扩展。

但是,您要求在(默认)交互式 shell 中使用双引号字符串,而不将字符串分成几部分。好吧,那怎么样:

$ a='!'
$ echo "hello${a}world"
hello!world

关于历史为什么?

为什么有一个特殊的案例!?

因为大部分ascii字符都是不是特别(内部"):

$ printf '%s\n' "\a\b\c\d\e\f...\z \!\@\#\%     \$a \`date\` \\"

\a\b\c\d\e\f...\z \!\@\#\%     $a `date` \

相关文字来自man bash将字符括在双引号中会保留引号内所有字符的字面值,但 $、`、\ 以及启用历史扩展时的 ! 除外。

这就是双引号内的反斜杠在古代 shell 中的工作方式,并且POSIX 规范反映出:

仅当被视为特殊时,<反斜杠> 后跟以下字符之一时,才应保留其作为转义字符的特殊含义(请参阅转义字符(反斜杠)):

$ ` " \ <换行>

答案2

显然,Bash 没有删除用于转义!出现在双引号内的反斜杠(以抑制历史扩展),已在错误打击邮件列表。

中提到的这种行为的历史原因你已有的答案确实是 Bash 的开发者和维护者给出的解释。引用 bug-bash切特·雷米的消息

根据记录,‘!’只能用单引号或反斜杠进行转义。双引号不起作用,因为“!”根据 POSIX.2 规范和传统 sh 行为,不是双引号内特殊处理的字符之一。

来自同一来源,关于如何处理!双引号内:

您可以使用“set +o histexpand”关闭历史扩展或在双引号外使用反斜杠。请注意,当 shell 不具有交互性时,通常不会启用历史扩展,因此删除脚本中的反斜杠应该不成问题。

(可以在该邮件列表上找到相同声明的一些变体,例如12,其中还提到了与C shell的关系)。

如果您无法使用这些解决方案中的任何一个:以下问题的答案中显示了各种解决方法如何回响一声巨响!,例如将 的第一个字符设置histchars为不太可能使用的字符,或使用同一变量的第三个字符来启动您不希望应用历史扩展的命令。

相关内容