[英]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.