21

ソース コードに対して 3 つのチェックをexit 0実行し、すべてのコマンドが成功したかexit 1、いずれかのコマンドが失敗したかどうかを確認する bash スクリプトがあります。

#!/bin/bash

test1 ./src/ --test-1=option
exit_1=$?

test2 ./src/ test-2-options
exit_2=$?

test3 ./src/ -t 3 -o options
exit_3=$?

# Exit with error if any of the above failed
[[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]]
exit $?

このコードは機能しますが、長すぎて冗長に感じます。これをより良くする方法はありますか?具体的には、私は満足していません:

  • コマンドを実行し、終了コードを変数に割り当てる必要がある
  • を使用し[[ ... ]]、次の行で終了コードを収集して終了する必要があります
  • [[ $var -eq 0 ]]のように、変数をブール値として扱うのではなく、変数を明示的に 0 と比較する必要がある

理想的には、最終結果は次のような読みやすいものになります。

exit_1=( test1 ./src/ --test-1=option )
exit_2=( test2 ./src/ test-2-options )
exit_3=( test3 ./src/ -t 3 -o options )

# Exit with error if any of the above failed
exit ( $exit_1 && $exit_2 && $exit_3 )

私が検討したいくつかのこと:


エラー コードを変数に 1 行で取得する:

exit_1=$( test1 ./src/ --test-1=option )$?
exit_2=$( test2 ./src/ test-2-options )$?
exit_3=$( test3 ./src/ -t 3 -o options )$?

これは機能し、これを少し短くしますが、他の人がこれを使用するのを見たことがありません. これは賢明で正気ですか?これに問題はありますか?


テストを実行するだけで、 && それらを一緒に:

test1 ./src/ --test-1=option && \
test2 ./src/ test-2-options && \
test3 ./src/ -t 3 -o options
status=$?

これは、bash の短絡として機能しません。失敗した場合test1、test2 と test3 は実行されないので、すべて実行する必要があります。


エラーを検出して終了する|| exit

[[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]] || exit 1

これにより、ぎこちない終了コードと変数を 1 行節約できますが、重要な部分exit 1が行末にあり、見落とす可能性があります。理想的には、次のようなものが機能します。

exit [[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]]

もちろん、エコーする代わりに出力を返すため、これは機能しません。[[

exit $( [[ $exit_1 -eq 0 && $exit_2 -eq 0 && $exit_3 -eq 0 ]] ; echo $? )

動作しますが、それでも恐ろしいクラッジのようです


exit-code-as-boolean を明示的に処理しない

[[ $exit_1 && $exit_2 && $exit_3 ]]

これは、あなたが望んでいることをしません。&& 変数に格納された 3 つのリターン コードを組み合わせる最も簡単な方法は、完全な$var -eq 0 && .... 確かにもっと良い方法はありますか?


私はbashが良いプログラミング言語ではないことを知っています-あなたがそれをそれと呼ぶことができるなら-しかし、これを少しでも簡単にする方法はありますか?

4

5 に答える 5

16

bashの算術コマンドを終了コードに一緒に使用ORし、結果を否定して、コードのいずれかがゼロでない場合に終了コード 1 を取得できます。まず、例:

$ ! (( 0 | 0 | 0 )); echo $?
0
$ ! (( 1 | 0 | 0 )); echo $?
1

今、あなたのスクリプト:

#!/bin/bash

test1 ./src/ --test-1=option; exit_1=$?
test2 ./src/ test-2-options;  exit_2=$?   
test3 ./src/ -t 3 -o options; exit_3=$?

# Exit with error if any of the above failed. No need for a final
# call to exit, if this is the last command in the script
! (( $exit_1 || $exit_2 || $exit_3 ))

または、一般に、任意の数のテストを実行すると、終了コードを蓄積できます。

#!/bin/bash

# Unfortunately, ||= is not an assignment operator in bash.
# You could use |=, I suppose; you may not be able to assign
# any meaning to any particular non-zero value, though.
test1 ./src/ --test-1=option; (( exit_status = exit_status || $? ))
test2 ./src/ test-2-options;  (( exit_status = exit_status || $? ))  
test3 ./src/ -t 3 -o options; (( exit_status = exit_status || $? ))
# ...
testn ./src "${final_option_list[@]}"; (( exit_status = exit_status || $? ))

exit $exit_status   # 0 if they all succeeded, 1 if any failed
于 2013-05-03T12:30:41.863 に答える
0

なぜ 3 つの異なる変数が必要なのですか?

fn() {
    local -i st
    test1 ./src/ --test-1=option
    st=$?

    test2 ./src/ test-2-options
    (( st = ($? || st) )) # Use arithmetic expression to or the values at each step

    test3 ./src/ -t 3 -o options
    (( 0 == ($? || st) ))
}
于 2013-05-03T12:08:16.457 に答える