web-dev-qa-db-ja.com

シェルスクリプトの一部が失敗した場合にシェルスクリプトを終了する方法は?

シェルスクリプトの一部が失敗した場合に終了するシェルスクリプトを作成するにはどうすればよいですか?たとえば、次のコードスニペットが失敗した場合、スクリプトは終了します。

n=0
until [ $n -ge 5 ]
do
  gksu *command* && break
  n=$[$n+1]
  sleep 3
58
Weylyn

1つのアプローチは、スクリプトの先頭にset -eを追加することです。つまり、(help setから):

  -e  Exit immediately if a command exits with a non-zero status.

したがって、コマンドのいずれかが失敗すると、スクリプトは終了します。

または、考えられる障害点に明示的なexitステートメントを追加できます。

command || exit 1
98
terdon

キーワードexitを使用して、任意の場所でスクリプトを終了できます。終了コードを指定して、スクリプトが失敗したこと、またはスクリプトがどのように失敗したかを他のプログラムに示すこともできます。 exit 1またはexit 2など(慣例により、終了コード0は成功を示し、0より大きいものは失敗を示します。ただし、慣例により、127を超える終了コードは異常終了のために予約されています(たとえば、信号))。

失敗時に終了する一般的な構造は、

if [ failure condition ]; then
    exit n
fi

適切なfailure conditionおよびnを使用します。ただし、特定のシナリオでは、異なる方法で進める場合があります。さて、あなたの場合のために、gksuの5つの呼び出しのいずれかが失敗すると、終了することになるというあなたの質問を解釈します。 1つの方法は、このような関数を使用することです

function try_command {
    for i in 1 2 3 4 5 ; do
        if gksu command ; then
            return 0
        fi
    fi
    exit 1
}

次に、try_commandによってループを呼び出します。

あなたの質問に対処する方法の(もっと)高度なまたは洗練された方法があります。ただし、上記のソリューションは、たとえばStephaneのソリューションよりも初心者がアクセスしやすくなっています。

17
countermode
_attempt=0
until gksu command; do
  attempt=$((attempt + 1))
  if [ "$attempt" -gt 5 ]; then
    exit 1
  fi
done
_

exitは、サブシェルで呼び出されない限り、スクリプトを終了します。スクリプトのその部分がサブシェルにある場合、たとえば、それが_(...)_または$(...)またはパイプラインの一部内にあるため、終了するだけですそのサブシェル =。

その場合、サブシェルに加えてscriptを終了するには、そのサブシェルの終了時にexitを呼び出す必要があります。

たとえば、ここでは2つのネストされたレベルのサブシェルがあります。

_(
  life=hard
  output=$(
    echo blah
    [ "$life" = easy ] || exit 1 # exit subshell
    echo blih not run
  ) || exit # if the subshell exits with a non-zero exit status,
            # exit as well with the same exit status

  echo not run either
) || exit # if the subshell exits with a non-zero exit status,
          # exit as well with the same exit status
_

サブシェルがパイプラインの一部である場合、それはよりトリッキーになる可能性があります。 bashには、zshの_$PIPESTATUS_配列に似た特別な_$pipestatus_配列があり、ここで役立ちます:

_{
   echo foo
   exit 1
   echo bar
} | wc -c
subshell_ret=${PIPESTATUS[0]}
if [ "$subshell_ret" -ne 0 ]; then
  exit "$subshell_ret"
fi
_
11

トラップはシグナルを受信するとアクションを実行します。

trap "echo EXIT;  exit" 0
trap "echo HUP;   exit" 1
trap "echo CTL-C; exit" 2
trap "echo QUIT;  exit" 3
trap "echo ERR;   exit" ERR
n=0
until [ $n -ge 5 ]
do
  n=$[$n+1]
  echo $n
  sleep 3
done

これを実行して、正常に終了させます。シグナル0でトラップします。

EXIT

もう一度実行して、^ Cで中断します。シグナル2とシグナル0の両方でトラップします。

CTL-C
EXIT

ゼロ以外の終了ステータスはERRでトラップされます

ERR
EXIT
3
RobP