Bash

如何在 vi 模式下搜尋 bash 的歷史記錄以查找“foo.*bar”

  • March 28, 2020

我的 bash 環境處於 vi 模式 ( set -o vi)。所以我可以先鍵入<ESC>/一個單詞,然後再輸入,然後 bash 在歷史記錄中搜尋該單詞。由於/也是vi的搜尋正則表達式的方法,所以我在bash也會搜尋正則表達式的表達式下。

不幸的是,當我輸入<ESC>/foo.*barbash 時,它在歷史記錄中找不到任何與正則表達式匹配的行foo.*bar

我是否忽略了某些東西,或者只是無法在歷史記錄中搜尋正則表達式?

簡短的回答是您不能使用正則表達式來搜尋 shell 歷史記錄。根據POSIX(類 Unix 作業系統的標準),您應該能夠使用正常shell 模式匹配(用於文件名萬用字元和 withcase語句)進行搜尋。這個特性被稱為非增量搜尋,但它目前似乎沒有在 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)如果可用,則使用)。

引用自:https://unix.stackexchange.com/questions/292952