如何在 vi 模式下搜尋 bash 的歷史記錄以查找“foo.*bar”
我的 bash 環境處於 vi 模式 (
set -o vi
)。所以我可以先鍵入<ESC>/
一個單詞,然後再輸入,然後 bash 在歷史記錄中搜尋該單詞。由於/
也是vi的搜尋正則表達式的方法,所以我在bash也會搜尋正則表達式的表達式下。不幸的是,當我輸入
<ESC>/foo.*bar
bash 時,它在歷史記錄中找不到任何與正則表達式匹配的行foo.*bar
。我是否忽略了某些東西,或者只是無法在歷史記錄中搜尋正則表達式?
簡短的回答是您不能使用正則表達式來搜尋 shell 歷史記錄。根據POSIX(類 Unix 作業系統的標準),您應該能夠使用正常shell 模式匹配(用於文件名萬用字元和 with
case
語句)進行搜尋。這個特性被稱為非增量搜尋,但它目前似乎沒有在 Bash 中正確實現。POSIX 規範
shell命令行編輯 (vi-mode)的 POSIX 規範聲明這些搜尋模式應該使用正常的 shell 模式匹配。雖然
^
元字元用於匹配行首,但它們不是正則表達式。
/pattern<newline>
向後移動命令歷史記錄,從上一個命令行開始搜尋指定的模式。模式使用模式匹配表示法中描述的模式匹配表示法 ,除了“^”字元作為模式的第一個字元出現時應具有特殊含義。在這種情況下,’^’ 被丟棄,’^’ 之後的字元只匹配行首。命令歷史中的命令應被視為字元串,而不是文件名。
記錄在案的 Bash 實現
Bash 使用GNU Readline庫來提供其互動式行編輯和歷史搜尋功能。Readline 庫的官方文件更側重於 Emacs 模式,但其手冊中的一小部分Readline vi Mode指出
雖然 Readline 庫沒有完整的 vi 編輯功能集,但它確實包含足以允許對行進行簡單編輯。
Readline vi 模式的行為與 POSIX 標準中指定的一樣。
實際的 Bash 實現
在兩個不同系統上進行了多次實驗後,我發現 Bash/Readline 中的非增量搜尋不像其官方文件中描述的那樣工作。我發現它
*
被視為文字星號,而不是匹配多個字元的模式。同樣,?
and[
也被視為文字字元。為了比較,我嘗試使用 Vi 模式
tcsh
並驗證它正確地實現了 POSIX 標準中指定的歷史搜尋。然後我下載並蒐索了 Readline 庫的程式碼,發現它的歷史搜尋功能使用簡單的子字元串搜尋,並且不使用任何搜尋模式元字元——除了插入符號,
^
(參見git 儲存庫中的search.c Readline 庫)。我認為 Bash/Readline 開發人員尚未實現此功能。我找不到錯誤列表,但
CHANGES
文件顯示他們一直在定期修復與 Vi-mode 相關的問題。更新:此功能已在 Readline 8.0(2019 年 1 月與 Bash 5.0 一起發布)中實現。如其CHANGES中所述:
Readline 中的新功能
一種。非增量 vi 模式搜尋 (
N
,n
) 可以搜尋外殼模式,如 Posix 指定的(fnmatch(3)
如果可用,則使用)。