Travis-CIで「検索」を使用して、特定のファイルタイプをプログラムでチェックしています。 (正確には、これはシェルチェックチェックです。)
ただし、find
を使用すると、「メインスクリプト」に渡されないため、コマンドによって実行されるコマンド/サブシェルの終了コードは自然に破棄されます。
例として、これは検索コマンドです。
find . -type f -iname "*.sh" -exec sh ./testScripts.sh "{}" \;
./testScripts.sh
は、テスト結果に応じて、0または> = 1で終了する場合があります。
testScripts.sh
は正しい終了コードで正しく終了しますが、find
により、コマンドの終了コードは常に "0"です。私が欲しいのは1つのファイル/実行エラーの場合、このエラーはTravis-CIまで「伝播」されるということです。
どうすればこれを達成できますか?
コメントでスティーブン・キットの提案を使用する:
_find . -type f -iname "*.sh" -exec sh -c 'for n; do ./testScripts.sh "$n" || exit 1; done' sh {} +
_
これにより、_sh -c
_が終了するとすぐに、_testScript.sh
_スクリプトがゼロ以外の終了ステータスで終了します。つまり、find
もゼロ以外の終了ステータスで終了します。
プラス記号で終了すると、プライマリが評価されるパス名がセットに集約され、
xargs(1)
と同様に、ユーティリティはセットごとに1回呼び出されます。 ゼロ以外の終了ステータスで呼び出しが終了した場合、find
は最終的には同様に終了しますですが、これによってfind
が早く終了することはありません。
コメントの質問について:
_for n; do ... ; done
_は奇妙に見えますが、何も繰り返す必要がないと、for
ループが暗黙的に_"$@"
_を反復することに気づくと意味があります。
末尾のsh
は、_$0
_シェルの_sh -c
_に配置されます。 _{}
_は、いくつかのパス名に置き換えられます。そこにsh
がないと、最初のパス名は_$0
_になってしまい、_$@
_にないため、ループによって取得されません。 _$0
_には通常、現在のインタープリターの名前が含まれます(_sh -c
_シェルによって生成されるエラーメッセージで使用されます)。
xargs
は、いずれかのコマンドが失敗した場合、1〜125の終了ステータス(GNU xargs
の123)で終了し、失敗した場合は中止されます。ステータスは255です。
xargs
の出力でfind
を確実に使用するには(-print0
)コマンドの標準入力を保持するには、GNU xargs
が必要です。したがって、GNU xargs
ksh
、zsh
またはbash
などのプロセス置換をサポートするシェル:
xargs -n1 -r0a <(find . -type f -iname '*.sh' -print0) sh ./testScripts.sh
または、最初に失敗したもので中止するには:
xargs -r0a <(find . -type f -iname '*.sh' -print0) sh -c '
for file do
sh ./testScripts.sh "$file" || exit 255
done' sh
(POSIXコード)の最初のエラー時にfind
を中止することもできます。
find . -type f -name '*.[sS][hH]' -exec sh -c '
for file do
if ! sh ./testScripts.sh "$file"; then
kill -s PIPE "$PPID"
exit 1
fi
done' sh {} +
(bash
のようないくつかのシェルでSIGPIPEをless noisy信号として使用)。これによりfind
が強制終了され、ゼロ以外の終了ステータスで戻ります。
(ここでは最後に)失敗したコマンドの終了ステータスの正確な値を取得するには、zsh
またはbash
を使用して、次のようにすることもできます。
ret=0
while IFS= read -rd '' -u3 file; do
sh ./testScripts.sh "$file" 3<&- || ret=$?
done 3< <(find . -type f -iname '*.sh' -print0)
zsh
を使用しても、find
は必要ありません。
set -o extendedglob
ret=0
for file (./**/*(#i).sh(D.)) {
./testScripts.sh $file || ret=$?
}