回响着“!” 字符串内部做了一些奇怪的事情

Bog*_*Bog 7 bash command-history zsh quoting history-expansion

如果我输入:

echo "Hello, World!"
Run Code Online (Sandbox Code Playgroud)

我不知道它的名字,但它提示我输入下一行。你知道这PS2件事。或者,如果您键入echo \并按Enter

为什么?

嗯,我知道这!是一个特殊变量,您可以使用它来引用您的历史记录。

但一旦我使用这个:

echo "Hello, World"!
Run Code Online (Sandbox Code Playgroud)

我得到了我想要的输出。发生了什么事,为什么不能!在内部使用""


感谢您的帮助 :)

Gil*_*il' 11

!不是特殊的_变量。(有一个名为 的变量!,您可以使用 访问它$!,但它是不相关的。)它是一个具有特殊含义的字符,具体取决于 bash 在哪里看到它以及后面的内容。

\n

角色!开始历史扩展。Bash 在解析命令行时,当它以交互方式读取命令时(不是当它运行脚本时,甚至是来自.交互式source命令行的脚本),很早就执行历史扩展。您可以设置该变量histchars来选择不同的字符!(但大多数其他 ASCII 字符会与常见用法发生冲突)。

\n

角色! 开始历史替换

\n
\n

除非后面跟有空格、制表符、行尾 \xe2\x80\x98=\xe2\x80\x99 或 \xe2\x80\x98(\xe2\x80\x99 (当启用 extglob shell 选项时)使用内置的shopt)。

\n
\n

echo "Hello, world"!所以类似or 的事情if ! grep -q foo myfile; \xe2\x80\xa6不会触发任何历史扩展。

\n

此外,单引号美元单引号可以防止历史扩展(即历史扩展字符在 内时没有其特殊含义\'\xe2\x80\xa6\'),并且引用字符的反斜杠可以保护该字符免于启动历史扩展,但双引号除非(自 bash 4.4 起)在 POSIX 兼容模式下调用 bash 时,否则不要这样做。也就是说,默认情况下,

\n
echo "!foo"\n
Run Code Online (Sandbox Code Playgroud)\n

制作!foo一个历史参考,该参考被替换在双引号内。您不能简单地在双引号字符串中包含实际的感叹号,因为其中echo "\\!foo"会包含反斜杠。你必须使用类似echo \\!"foo"或 的东西echo \'!foo\'。我不知道 bash 为何这样做:这是 20 世纪 80 年代做出的设计决策。(Bash 从 csh 继承了历史扩展,但情况更糟:即使是单引号也不能防止历史扩展。)

\n

但我无法重现这个确切的情况:

\n
bash-5.0$ echo "Hello, World!"\nHello, World!\n
Run Code Online (Sandbox Code Playgroud)\n

但这可能取决于 bash 的版本或配置。双引号本身不会抑制历史扩展:事实上,它!"不适合任何形式的事件指示符

\n
bash-5.0$ echo "Hello!world"\nbash: !world: event not found`\n
Run Code Online (Sandbox Code Playgroud)\n


roa*_*ima 6

假设您使用bashas 标记,请使用单引号而不是双引号

echo 'Hello, World!'
Hello, World!
Run Code Online (Sandbox Code Playgroud)

不过,我认为您更有可能使用zsh,并且适用相同的修复:

echo "Hello, World!"
dquote>

echo 'Hello, World!'
Hello, World!
Run Code Online (Sandbox Code Playgroud)

请参阅shell 中的 "..."、'...'、$'...' 和 $"..." 引号之间有什么区别?有关不同类型的报价以及何时(不)使用它们的更多信息。

  • 你是对的,在 `echo "stuff!"` 之后显示第二个提示看起来像 zsh 的东西。在 zsh 中,另一个解决方法是 `echo "stuff\!"`。 (2认同)