私は現在非常に単純なzshスクリプトを書いています。私が通常することは次のとおりです。
mv */*.{a,b} .
zshスクリプトで実行すると、サイズが異なるように調整され、インタラクティブモードで作業すると失敗します。
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% mv */*.{a,b} .
% ls file.a
file.a
したがって、これはうまくいきますが、スクリプトでは次のようになります。
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% cat script.sh
#!/usr/bin/zsh
mv */*.{a,b} .
% ./script.sh
./script.sh:2: no matches found: */*.b
では、違いは何ですか?私は何が間違っていましたか?
答え1
両方のデフォルトオプション設定が正しくありませんzsh
。代わりにasコマンドを使用すると、echo
何が起こっているのかを簡単に確認できますmv
。
null_glob
インタラクティブにオプションを設定したようです。zsh
ドキュメントによると、このオプションはデフォルトでは設定されていません。このオプションをオフにするとどうなりますか?nomatch
他のオプションが設定されているかどうかによって異なります。nomatch
unset( ) を使用すると、nonomatch
次のような結果が得られます。
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% echo */*.{a,b} .
dir/file.a */*.b .
拡張は2つの段階で行われます。まず、*/*.{a,b}
2 単語に拡張します。*/*.a
and */*.b
。その後、各単語はグローバルパターンに展開されます。最初のものdir/file.a
は一致するものがないため、2番目のものは独自に拡張され、2番目のものは独自に拡張されます。これが意味するのは、mv
and not を使用する場合は、echo
2 つのファイル (音) と (該当ファイルなし) をmv
移動しなければならないということです。これは、などのほとんどのシェルでデフォルトで発生します。dir/file.a
*/*.b
sh
ksg
bash
zsh デフォルトオプションの設定はnull_glob
設定されずにnomatch
設定されます。スクリプトはデフォルトのオプション設定で実行されます(実際に~/.zshenv
変更しないでください、または変更/etc/zshenv
しない限り)。これはスクリプトから次のことを意味します。
% mkdir dir
% touch dir/file.a
% ls file.a
ls: cannot access file.a: No such file or directory
% cat script.sh
#!/usr/bin/zsh
echo */*.{a,b} .
% ./script.sh
./script.sh:2: no matches found: */*.b
一致するものがないため、*/*.b
エラーが発生しますnomatch
。
/ commandの前にスクリプトを挿入すると、上記のsetopt nonomatch
誤った動作に戻ります。存在しないファイルを移動しようとします。echo
mv
/コマンドの前にスクリプトを挿入すると、setopt null_glob
有効なインタラクティブシェルから得られる動作が得られます。echo
mv
答え2
zshをインタラクティブに実行すると~/.zshrc
(そしてシステムを読みます/etc/zshrc
が、管理者がいたずらでない限りそれは犯人ではありません)。一部を設定することもできます。オプション特にzshがコマンドを拡張する方法が修正されましたextended_glob
(zshが1990年代初頭に以前のバージョンとの互換性を選択しなかった場合は、このオプションが存在しなかったときにこれがデフォルトでなければなりませんでした)。これらのオプションは、スクリプトの実行時に設定されません。
あなたの場合、コマンドはmv */*.{a,b} .
最初に単語リストに解析されますmv
。*/*.a
、、 (*/*.b
中.
括弧拡張をオフにしない限り)。その後、ワイルドカード文字を含む各単語はグローバルパターンと見なされます。デフォルトでは、zshはglobパターンがどのファイルとも一致しない場合、コマンドは実行されず、zshからエラー信号を送信します。明らかに、対応.zshrc
するnull_glob
オプションをオンにすると、一致しないパターンが空の単語リストに展開されます(つまり削除されます)。スクリプトを実行すると、2番目のパターンが*/*.b
どのファイルとも一致しないため、表示されるエラーが発生します。コマンドを対話的に実行すると、モードは削除されます。
null_glob
スクリプトを使用して明示的にこのオプションを設定できますsetopt null_glob
。以下を使用して特定のモードをオンにすることもできます。N
グローバル予選:
mv */*.{a,b}(N) .
ここでは中括弧拡張を使用しないでください。代わりに、以下を使用してください。これまたはオペレーター(通常のshとは異なり)zshで使用できます。これは、2つのパターンではなく、2つのパターンのいずれかに一致するファイルを意味するためです。
mv */*.(a|b) .
これにより、パターンが1つだけで、その単一のパターンに一致するファイルがない場合にのみエラーが発生します。
このコマンドは、一致するファイルがまったくない場合にエラーを発生させます。(N)
誤ったコマンドが実行される可能性があるため、ミュートすることはできません。mv .
代わりに、最初に一致するものがあるかどうかをテストし、mv
一致するものがある場合にのみ実行してください。
files=(*.(a|b)(N))
if ((#files)); then mv -- $files[@] .; fi