Zsh は文字列をファイル名パターンとして扱い、それについて文句を言っています (NOMATCH オプション)

Zsh は文字列をファイル名パターンとして扱い、それについて文句を言っています (NOMATCH オプション)

私は 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内のディレクトリを検索します。../foobar

したがって、は、現在のディレクトリのすべてのサブディレクトリ (の直後に がある^/dev/tty[1-7]$ため、何も除外されません) で、、、...という名前のファイルを検索しようとします。 は、 1 から 7 までの範囲の 1 つの文字に正確に一致するため、その場合、 は特別に扱われません。^/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]$

setがない場合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$

まとめると、正規表現パターンを引用することは私にとっては常に良いアイデアのように思えますが、通常はキーストロークを節約するようにもしています。

関連情報