できない.dev

zsh で「no matches found」が出てコマンドを実行できない

Zsh は既定でグロブに一致するファイルが無いとエラーにする(NOMATCH)。
Bash のようにパターンをそのまま引数へ渡さないため、[]* を含む引数はクオートするか noglob を付けて実行する。

公開:

要約

zsh: no matches found: uvicorn[standard] のようなエラーは、コマンドが実行される前に Zsh がその引数をファイル名パターンとして展開しようとして失敗したことを示す。
コマンド自体はまだ動いていない。

Zsh には NOMATCH というオプションがあり、公式ドキュメントでは「ファイル名生成のパターンが何にも一致しなかった場合、引数リストにそのまま残す代わりにエラーを表示する」と定義されている。
Zsh の既定ではこれが有効なので、一致するファイルが無い時点で実行が止まる。
Bash はパターンをそのまま渡すため、同じコマンドが Bash では通り Zsh では落ちる。

よくある原因

  1. 角括弧を含む引数。
    Python の extras 指定(pip install uvicorn[standard])が代表例である。[...] は文字クラスのパターンなので、カレントディレクトリに該当ファイルが無ければエラーになる。
  2. *? をクオートせずに渡している。find . -name *.log のように、コマンド側に渡したいパターンをシェルが先に食べてしまう。
  3. EXTENDED_GLOB を有効にしている。
    この場合 #~^ もパターン文字として扱われるため、npm i pkg@^1.0.0 のような指定まで対象になる。
    フレームワーク付きの設定ファイルを使っていると気づかないうちに有効になっていることがある。
  4. リモート側で展開させたいパターン。scp host:/var/log/*.log . はローカルで先に展開されるため、手元に該当ファイルが無ければエラーになる。

解決策

1. クオートする(推奨)

もっとも影響範囲が狭く、他のシェルでも通る書き方である。

pip install 'uvicorn[standard]'
find . -name '*.log'
scp host:'/var/log/*.log' .

2. コマンド単位でグロブを止める

引数が多くクオートが煩雑な場合は noglob を前置する。
そのコマンドの実行に限りファイル名生成が無効になる。

noglob pip install uvicorn[standard]

よく使うコマンドなら alias にしておく手もある。

alias pip='noglob pip'

3. シェルの挙動そのものを変える

setopt nonomatch

NOMATCH を無効にすると、一致しないパターンは Bash と同じくそのまま引数として渡る。
ただし打ち間違えたパターンも静かに通るようになるため、.zshrc へ恒久設定として書く前に副作用を確認しておく。

現在の設定は次のコマンドで確認できる。

setopt | grep -i nomatch

4. どの文字が原因かを切り分ける

echo pkg[extra]

echo だけでも同じエラーが出れば、原因はコマンドではなくシェルの展開である。
ここでエラーにならないなら、問題はコマンド側の引数解釈にある。

この記事は役立ちましたか?