[英]Single quotes in history expansion (bash)
我对Bash的语法有理论上的疑问。
我正在Linux Ubuntu 14.04中运行Bash 4.3.11(1)。
在GNU官方网站上: Bash官方网站(GNU)
在9.3.1节中。 它说:
!串
请参考历史记录列表中当前位置之前的最新命令(以string开头)。
一般来说,从语法上来说, string
是一系列在第一个空格或换行符之前结束的字符序列。
但是,当在3.1.2节中描述报价时,我们可以在3.1.2.2节中阅读。 结果如下:
将字符括在单引号(''')中可保留引号内每个字符的字面值。
特别是,单引号内的空格不会使单词分开。
因此,像!'some text'
这样的表达式必须在Bash的历史列表中搜索以'some text'
开头的最新命令。
但是,当我在终端中写入text
时, some
text
与text
之间的空格被打破了,因为显示了以下错误消息:
bash:!'some:未找到事件
这种行为是Shell实施中的错误吗?还是我不了解此示例的Bash扩展规则?
我不会将观察到的行为称为错误,因为除了bash shell本身的观察到的行为之外,没有关于历史扩展的规范。 但是,可以肯定的是,没有很好地记录解析历史扩展表达式的精确机制,并且有很多可能令人惊讶的极端情况。
bash手册页确实指出“历史扩展”是在读取完整行之后立即执行的, 在shell将其分解为单词之前 (添加了强调),而bash手册提到历史扩展是由“历史”库提供的。 这是大多数历史扩展解析异常的根本原因:历史扩展无需bash令牌生成器的任何帮助即可在未解析的原始输入上进行工作,并且大部分是通过非bash特定的外部库完成的。 由于标记化bash
输入是不平凡的,因此历史扩展期间使用的相对简单的解析规则只是对真实bash解析的粗略近似,这并不令人感到意外。
例如,bash手册确实指示您可以通过用反斜杠引号来防止识别历史扩展字符( ! )。 但是没有明确记录任何紧跟在!前面的\\ 。 即使反斜杠本身用反斜杠引起来,也会抑制对历史扩展的识别。 所以! \\\\!word
中的in 不会导致替换以word
开头的先前命令。 ( \\\\word
是执行命令 word
而不是别 word
一种常见方法,因此该示例并非完全是人为设计的。)
在此答案中,可以找到有关历史扩展字符识别的一些特殊情况的详细讨论。
这个问题引起的问题稍有不同,因为它与历史扩展解析的下一阶段有关。 一旦确定特定字符是历史扩展字符,则有必要解析随后的“事件”。 如bash手册所示,该事件可以采用多种形式,其中一种是!string
,代表以“ string
”开头的最新命令。
暗示仅当没有其他形式适用时才使用此形式,这意味着string
不能以数字或- ,!开头。 , #或? 。 它也可能不以空格或=开头(因为它们会禁止历史扩展),并且在某些情况下(或“ (可能会阻止历史扩展)。最后,它也可能不会以^ , $ , %或*开头被解释为单词指示符(来自默认事件,即上一个命令)。
bash手册未指定终止string
。 它在history
库手册中有半篇文档介绍,其中提到历史记录搜索字符串(或bash手册中称为“事件”)以空格, :或历史记录配置变量history_search_delimiter_chars
中的任何字符终止。 (为了记录, bash
当前(v4.3)将该变量设置为";&()|<>"
。)
如前所述,在决定是否识别历史扩展字符时,应考虑引用。 事实证明,如果历史记录扩展发生在双引号字符串内,则也将闭双引号视为历史记录搜索定界符。 据我所知,这就是将分隔!string
的整个字符列表。
在bash和历史记录文档中都没有任何地方声明可以通过引用使历史记录搜索分隔符成为非特殊字符,并且实际上不会发生。 一个开放的报价,无论是双人或单人,甚至是一个反斜杠继 ! 将被视为要搜索的string
一部分,而无需任何特殊处理。
子字符串匹配历史扩展的解析- !?string?
-完全不同。 该字符串只能以?结尾。 或换行符。 (如bash手册所述,如果以换行符结尾,则尾随?是可选的。)
一旦识别了历史扩展字符并且已经识别了历史搜索字符串,则可能有必要将检索到的历史条目拆分为单词。 同样,bash手册对拐角处的情况略有轻率,它说“该行以与Bash相同的方式分解为单词,因此用引号引起的几个单词被认为是一个单词”。
一个学徒会观察到“以与Bash相同的方式”与说“完全像Bash那样”并不完全相同,实际上该句子的第二部分是按字面意思写的:用引号括起来的几个单词被认为是一个单词。 即使引号并非真正匹配的引号 。 例如,该行:
command "$(echo " foo bar ")"
历史库认为它由以下五个词组成:
0. command
1. "$(echo "
2. foo
3. bar
4. ")"
尽管bash解析会大不相同。 相比之下,bash和历史库在解析
command "$(echo ' foo bar ')"
两个字。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.