历史扩展中的单引号(bash)

时间:2015-01-01 23:33:10

标签: linux string bash syntax

我对Bash的语法有一个理论上的问题 我在Linux Ubuntu 14.04中运行Bash 4.3.11(1)。

在官方GNU的网站上:Bash official web (GNU)
在Subection 9.3.1中。它说:

  

!串

     

请参阅当前位置之前的最新命令      在以字符串开头的历史列表中。

一般来说,从理论上讲,string是在第一个空格或换行符之前结束的字符序列。

但是,在3.1.2。小节中描述引用时,我们可以在第3.1.2.2段中读到。以下是:

  

用单引号括起字符(''')保留字面值   引号内每个字符的值。

特别是,单引号内的空格不会用分隔的单词来表示字符串。

因此,像!'some text'这样的表达式必须在Bash的历史列表中搜索从'some text'开始的最新命令。

但是,当我在终端中写入时sometext之间的空白被破坏,因为显示以下错误消息:

  

bash:!' some:event not found

这种行为是shell实现中的一个错误,还是我不了解Bash的扩展规则?

1 个答案:

答案 0 :(得分:2)

我不会将观察到的行为称为错误,因为除了观察到的bash shell本身的行为之外,没有规范历史扩展。但肯定的是,解析历史扩展表达式的精确机制没有很好的记录,并且有很多可能令人惊讶的极端情况。

bash联机帮助页确实说明历史扩展"是在读完整行之后立即执行的,在shell将其分解为单词之前" (重点补充),而bash手册提到历史扩展是由历史库提供的。这是解决奇怪问题的大多数历史扩展的根本原因:历史扩展在没有来自bash tokenizer的任何帮助的情况下对原始未解析的输入起作用,并且主要使用不是特定于bash的外部库来完成。由于对bash输入进行标记化并非易事,因此在历史扩展期间使用的相对简单的解析规则只是对真正的bash解析的粗略近似并不奇怪。

例如,bash手册确实表明您可以通过反斜杠引用来阻止历史记录扩展字符()被识别。但是没有明确记录任何紧接在之前的 \ 将禁止识别历史扩展,即使反斜杠本身用反斜杠引用也是如此。所以\\!word中的确实导致以word开头的上一个命令被替换。 (\\word是执行命令 word而不是别名 word的常用方法,因此示例并非完全做作。)

可以在this answer中找到关于识别历史扩展字符的一些极端案例的更长时间讨论。

这个问题提出的问题略有不同,因为它是关于历史扩展解析的下一阶段。一旦确定特定字符是历史扩展字符,就必须解析"事件"以下;如bash手册所示,该事件可以采用多种形式,其中一种形式为!string,代表最新的命令,以" string"开始。

暗示只有在没有其他形式适用的情况下才会使用此表单,这意味着string可能不会以数字开头或 - 。它也可能不是以空格或 = 开头(因为那些会抑制历史扩展),在某些情况下" (其中)可能会抑制历史扩展)。最后,它可能不会以 ^ $ * 开头,这将被解释为一个单词指示符(来自默认事件,这是上一个命令)。

bash manual未指定终止string的内容。它在history library manual中有半文档记录,其中提到历史搜索字符串(或者&#34;事件&#34;因为它在bash手册中调用)由空格终止,,或历史配置变量history_search_delimiter_chars中的任何字符。 (对于记录,当前bash(v4.3)将该变量设置为";&()|<>"。)

如前所述,在决定是否识别历史扩展字符时会考虑引用;事实证明,如果历史扩展发生在双引号字符串中,则结束双引号也被视为历史搜索分隔符。据我所知,这是将划分!string的整个字符列表。

无论是bash还是历史文档都没有说明历史搜索分隔符可以通过引用变得非特殊,实际上这不会发生。一个开放的引用,无论是双引号还是单引号,甚至是反斜杠跟随,都将被视为要搜索的string的一部分,而不是特殊处理。

解析子字符串匹配历史记录扩展 - !?string? - 完全不同。该字符串只能由或换行符终止。 (正如bash手册所说,如果用换行符终止,则尾随是可选的。)

一旦识别了历史扩展字符并且识别了历史搜索字符串,则可能需要将检索到的历史记录条目拆分为单词。再说一遍,bash手册对于角落的情况略显傲慢,当它说&#34;这条线以与Bash相同的方式被分成单词时,所以被引号包围的几个单词被认为是一个单词。&#34;

一个学究会以与Bash相同的方式观察到&#34;&#34;与Bash所说的完全相同&#34;并且实际上句子的第二部分是真实的:被引号括起来的几个单词被认为是一个单词,即使引号是没有真正匹配的报价。例如,行:

command "$(echo " foo bar ")"
历史库将

视为由以下五个单词组成:

0. command
1. "$(echo "
2. foo
3. bar
4. ")"

虽然bash解析会有很大的不同。相比之下,bash和历史库同意解析

command "$(echo ' foo bar ')"

两个字。