Shell

Bash 萬用字元的歷史

  • June 5, 2018

Bash“萬用字元”和正則表達式不相同是否有歷史原因?例如,我相信在 Bash[1-2]*中匹配以 1 或 2 開頭的任何內容,然後是其他任何內容,而作為正則表達式[1-2]*將僅匹配 1 和 2 的序列。我的 Bash 腳本和 REGEX foo 都很弱,我經常遇到與這些差異相關的問題,這讓我很好奇它們為什麼不同。

bash最初在 80 年代後期設計為ksh具有 csh/tcsh 的一些互動功能的部分複製。

globbing 的起源必須在它所建立的那些早期的 shell 中找到。

ksh它本身就是 Bourne shell 的擴展。Bourne shell 本身(於 1979 年在 Unix V7 中首次發布)是一個從頭開始的干淨實現,但它並沒有完全脫離 Thompson shell(V1 -> V6 的 shell)並結合了 Mashey shell 的功能。

特別是,命令參數仍然由空格分隔,|現在是新的管道運算符,但^仍被支持作為替代(並解釋了為什麼你這樣做[!a-z]和不這樣做[^a-z]),$1仍然是腳本的第一個參數,反斜杠仍然是轉義字元. 許多正則表達式運算符 ( ^\|$) 在 shell 中都有自己的特殊含義。

Thompson shell 依賴外部實用程序進行通配。當在命令中sh找到 unquoted或s 時*,它將通過.[``?``glob

rm *.txt

最終會執行 glob 為:

["glob", "rm", "*.txt"]

並且 glob 最終會rm以匹配該模式的文件列表執行。

grep a.\*b *.txt

將執行glob為:

["glob", "grep", "a.\252b", "*.txt"]

通過在該*字元上設置第 8 位來引用上述內容,以防止glob將其視為萬用字元。glob然後會在呼叫grep.

用正則表達式做同樣的事情,那就是:

regexp rm '\.txt$'

或者:

regexp rm '^[^.].*\.txt$'

排除點文件。

由於運算符兼作 shell 特殊字元,因此需要轉義運算符,.文件名中常見的 regexp 運算符這一事實使得匹配文件名不太合適,並且對於初學者來說很複雜。在大多數情況下,您只需要可以替換一個 ( ) 或任意數量 ( ) 個字元的萬用字元。?``*

現在,不同的 shell 添加了不同的萬用字元。如今,ksh 和 zsh glob(在某種程度上bash -O extglob實現了 ksh glob 的子集)在功能上等同於正則表達式,其語法與文件名和目前的 shell 語法一起使用不太麻煩。例如,在zsh(使用extendedglob 擴展)中,您可以執行以下操作:

echo a#.txt

如果您希望(不太可能)匹配由a後跟.txt. 比echo (^a*\.txt$)(這裡使用大括號將正則表達式運算符與 shell 運算符隔離開來,這可能是 shell 處理它的一種方式)更容易。

echo (foo|bar|<1-20>).(#i)mpg

對於基本名稱為 foo、bar 或 1 到 20 的十進制數的 mpg 文件(不區分大小寫)…

ksh93now 還可以在其 glob 中包含正則表達式(基本的、擴展的、類似 perl 或“增強的”)(儘管它有很多錯誤),甚至提供了一個在 glob 和正則表達式 ( printf %R, printf %P) 之間轉換的工具:

echo ~(Ei:.*\.txt)

以擴展正則表達式匹配(非隱藏)txt 文件,不區分****大小寫

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