エラーにもかかわらず、ダッシュシェルスクリプトを実行し続けるには?

エラーにもかかわらず、ダッシュシェルスクリプトを実行し続けるには?

ファイルの最後まで実行するように設計されたダッシュシェルスクリプトがあります。

#!/usr/bin/dash
# File b_shell
. a_nonexistent_file
echo "I want to print this line despite any previous error."

ただし、存在しないファイルのインポートに失敗すると、実行は停止します。

$ ./b_shell
./b_shell: 3: .: a_nonexistent_file: not found

インターネット上で簡単に見つけることができるなどset -eの候補ソリューションを試してみましたが、役に立ちませんでした。|| true

追加情報:

  1. Bash、tcshなどの他のシェルは使用できません。俺を変えないでください。
  2. 以下のようにスクリプトを停止しない他の「見つかりません」エラーが見つかりました。
#!/usr/bin/dash
# File b_shell_ok
a_nonexistent_command
ls a_nonexistent_file
echo "This line is printed despite any previous error."
$ ./b_shell_ok
./b_shell_ok: 3: a_nonexistent_command: not found
ls: cannot access 'a_nonexistent_file': No such file or directory
This line is printed despite any previous error.

答え1

.特別な組み込み関数だからです。これは POSIX 要件です。他のほとんどのPOSIXシェルもこれを行いますが、それが対応するposix / sh / kshモードにある場合にのみ(呼び出し時に含まれますbash)。zshsh

特殊な組み込み関数の特殊性を排除するPOSIXメソッドは、その関数に接頭辞を付けることですcommand

$ dash -c 'command . /x; echo here'
dash: 1: .: cannot open /x: No such file
here

exitこれは、ソースファイルの呼び出し中またはコンテンツの解釈中に致命的なエラーが発生した場合にシェルが終了するのを防ぎません。ダッシュ(たとえば反対)の場合、bash -o posixソースファイルに埋め込まれた特殊関数が失敗してもシェルは終了しませんcommand

このオプションも有効な場合、errexitソースファイルを開くことができない場合、シェルは終了し続けますが、今回はゼロ以外のcommand終了ステータスを返します。

$ dash -o errexit -c 'command . /x; echo "$? here"'
dash: 1: .: cannot open /x: No such file

解決策はエラーを処理することです。

$ dash -o errexit -c 'command . /x || echo "that is fine"; echo "$? here"'
dash: 1: .: cannot open /x: No such file
that is fine
0 here

または:

$ dash -o errexit -c 'command . /x && : non-fatal; echo "$? here"'
dash: 1: .: cannot open /x: No such file
2 here

(またはcommand .//ステートメントの条件付き部分を呼び出します)。ifwhileuntil

この場合(例とは異なり、dash少なくとも現在のバージョン)、ソースファイルのコード評価効果はキャンセルされません。bash -o posixerrexit

$ dash -ec 'command . ./file || echo fine; echo here'
before
$ bash -o posix -ec 'command . ./file || echo fine; echo x'
before
after
x

errexit最も単純なスクリプトを除いて、いくつかの理由の1つで避けるのが最善です。

zsh はcommandPOSIX よりも先行し、意味が異なります。command .sh エミュレーション/POSIX モードでない場合は使用できません。

このエラーを回避するには、stderrの削除中に一部のfdでファイルを開き、事前にTOCTOUレースに付属のチェックを実行するのではなく、そのファイルをインポートできます/dev/fd/n

$ dash -c '{ command . /dev/fd/3; } 4>&2 2> /dev/null 3< file 2>&4 4>&-; echo here'
here

リダイレクトが失敗した場合、リダイレクトされたコマンド(ここではコマンドグループ) が実行されないため、シェルは特殊な組み込み機能を実行しようとしないため、シェルのシャットダウンによる副作用を回避できます. OSがLinuxまたはCygwinで、オープンがaと等しくないcommand場合は、プレフィックスを追加し、ファイルがfd 3で開かれてからファイル権限が変更された場合でも、失敗する可能性があります。/dev/fd/xdup(x)

答え2

それPOSIXの要件このような失敗はシェルを停止する必要があります。

読み取り可能なファイルがない場合、非対話型シェルは終了します。

したがって、唯一のオプションは、ファイルが存在し、必要に応じて読み取り可能であることを確認してコマンドを保護することです。

[ -f file ] && [ -r file ] && . ./file

ifファイルが存在しない場合は、エラーまたは警告メッセージを印刷するためにそれを完全なステートメントに拡張することもできます。

関連情報