私は次に見つかったすべての実行可能プログラムを書くための短いスクリプトを書こうとしています$PATH
。
for dir in $(tr ':' ' ' <<<"${PATH}"); do
for pgm in $dir/*; do
if command -v "${pgm}" >/dev/null 2>&1; then
echo "${pgm}"
fi
done
done | sort >file
Bashでは期待どおりに機能しますが、内部ループでファイル名の生成が失敗した場合、zshはスクリプトの処理を停止します。
for pgm in $dir/*; do
^^^^^^
...
done
その結果、myには$PATH
ファイル()を含まないディレクトリが含まれているため、/usr/local/sbin
zshではスクリプトは後でディレクトリにある実行可能ファイルに書き込むことができません。
同じ問題を示す別のコードは次のとおりです。
for f in /not_a_dir/*; do
echo 'in the loop'
done
echo 'after the loop'
Bashでは、このコマンドは次のように出力します。
in the loop
after the loop
コードを使用して終了します0
。
zsh では同じコマンドが出力されます。
no matches found: /not_a_dir/*
コードを使用して終了します1
。
シェル間の動作の違いは、以下のnomatch
ようにoptionsから来ているようですman zshoptions
。
一致しない(+3)<C> <Z>
ファイル名生成パターンに一致する項目がない場合は、引数リストに変更せずにそのままにする代わりにエラーが出力されます。これは初期
~
にも適用されます=
。
man zshexpn
(ファイル名生成セクション)に記載されています。
その単語は、パターンに一致するソートされたファイル名のリストに置き換えられます。一致するパターンが見つからない場合、NULL_GLOB オプションが設定されて単語が削除されるか、NOMATCH オプションが設定解除されて単語が変更されない限り、シェルはエラーメッセージを表示します。
設定を解除すると、nomatch
zsh は bash のように動作します。
unsetopt nomatch
for f in /not_a_dir/*; do
echo 'in the loop'
done
echo 'after the loop'
bashとzshの動作の違いとスクリプトがzshでエラーを引き起こす理由を理解していますが、ファイル名の生成に失敗した場合はzshがすぐにスクリプトの処理を停止する理由を理解したいと思います。そのため、失敗したファイル名の生成を失敗したコマンドに置き換えて、同じ問題を(実行を通じて)再現しようとしましたnot_a_cmd
。
for f in ~/*; do
not_a_cmd
done
echo 'after the loop'
ただし、スクリプトの出力は両方のシェルでほぼ同じです(エラーメッセージを除くnot_a_cmd
)。特に、両方のシェルは以下を印刷します。
after the loop
両方のシェルはコードで終了します0
。
失敗したファイル名の生成(例for f in /not_a_dir/*
:)によってzshがスクリプトの処理を停止しますが、失敗したコマンド(例not_a_cmd
:)が停止しないのはなぜですか?
私はそれを使用していますzsh 5.6.2-dev-0 (x86_64-pc-linux-gnu)
。
答え1
これはバグではなく機能です。