我正在嘗試來自 Bash 的 Zsh。我有點難以理解為什麼 Zsh 抱怨 grep 正規表示式。
usr@rk1 ~ % tty | grep ^/dev/tty[1-7]$ > /dev/null 2>&1
zsh: no matches found: ^/dev/tty[1-7]$
我注意到輸出消失了,如果(1)我將正則表達式放在引號內,(2)從正則表達式中刪除斜杠或(3)使用setopt NO_NOMATCH
.
來自 zshoptions 手冊:
不符 (+3) <C> <Z>
如果檔案名稱產生模式沒有匹配項,則列印錯誤,而不是將其保留在參數清單中不變。這也適用於初始“~”或“=”的檔案擴充。
因此,在我看來,由於斜杠,正則表達式被視為檔案名稱模式。這被認為是正常現象還是錯誤?
另外,如果能有類似 GreyCat 的 Bashism 和 BashPitfalls 頁面但針對 Zsh 的東西那就太好了。你知道這樣的資源嗎?
答案1
如果您設定了該EXTENDED_GLOB
選項,則該模式^something
將用於檔案名稱產生。來自zshexpn手冊頁:
^x
(需要設定 EXTENDED_GLOB。)符合模式 x 以外的任何內容。它的優先權高於/
,因此^foo/bar
將搜尋.
除名./foo
為 的檔案之外的目錄bar
。
因此,^/dev/tty[1-7]$
正在嘗試在當前目錄的每個子目錄(不排除任何內容,因為^
後面直接跟著)中查找名為, , .../
的文件,該文件與 1 到 7 之間的範圍內的一個字符完全匹配。dev/tty1$
dev/tty2$
dev/tty7$
[1-7]
$
您已經找到了解決方案,設定NO_NOMATCH
(可能很危險,但我非常喜歡它,因為我懶於打字;)
)或引用(單引號或雙引號)插入符號。
試試print
正在發生的事情:
$ setopt nomatch extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$
# ^ is doing filename generation in every sub-dir
$ touch foo/dev/tty5$
$ echo ^/dev/tty[1-7]$
foo/dev/tty5$
# quote to prevent filename generation
$ echo "^/dev/tty[1-7]$"
^/dev/tty[1-7]$
$ echo '^/dev/tty[1-7]$'
^/dev/tty[1-7]$
如果沒有EXTENDED_GLOB
設置,插入符號將按字面解釋為普通字元。所以引用又是你的朋友了——這次只有[1-7]
觸發檔名生成:
$ setopt nomatch no_extended_glob
$ echo ^/dev/tty[1-7]$
zsh: no matches found: ^/dev/tty[1-7]$
# quote to prevent filename generation
$ echo ^/dev/tty"[1-7]"$
^/dev/tty[1-7]$
# caret is interpreted literally
$ mkdir ^/dev -p
$ touch ^/dev/tty5$
$ echo ^/dev/tty[1-7]$
^/dev/tty5$
所以,總結一下:引用正規表示式模式對我來說似乎總是一個好主意——儘管我通常也會嘗試節省一些按鍵。