コマンドが失敗した場合のシェルスクリプトの中止
1. 概要
Bashスクリプトを使用すると、強力なツールを利用できます。 Bashスクリプトは、複数のコマンドを連続して実行するための優れた方法です。 スクリプトを作成するときは、1つのコマンドが失敗しても、後続のすべてのコマンドが実行されることを忘れないでください。 この記事では、いくつかのセーフガードを追加することでこれを防ぐ方法を学びます。
2. 問題
まず、bashスクリプトがデフォルトでエラーを処理する方法を見てみましょう。 「hello」と「world」という単語を出力する単純なスクリプトhello.shがあるとします。
#!/bin/bash
echo hello
echo world
それを実行すると、望ましい結果が得られます。
$ ./hello.sh
hello
world
次に、失敗することが保証されているステートメントを追加しましょう。
#!/bin/bash
echo hello
cat non-existing-file
echo world
このスクリプトを実行すると、エラーが出力されます。 ただし、実行は停止せず、「world」は引き続き出力されます。
$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
world
また、スクリプトの終了コードがゼロになり、すべてが正常であることを示します。
$ echo $?
0
3. 最初のエラーで終了
発生した最初のエラーで、ゼロ以外の終了コードでスクリプトを終了させたいとしましょう。 したがって、 set を使用して、スクリプトの開始時にシェルのデフォルトの動作を変更する必要があります。
#!/bin/bash
set -e
echo hello
cat non-existing-file
echo world
最初の行にset-e を指定して、最初のエラーで実行を停止するようにBashに指示します。
$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
また、返される終了コードは、失敗したコマンドの終了コードと同じです。
$ echo $?
1
4. pipefailを使用する
残念ながら、このソリューションはパイプステートメントを含むスクリプトでは機能しません。 たとえば、失敗したコマンドから始めて、最初の2つのコマンドをパイプでつなぎます。
#!/bin/bash
set -e
cat non-existing-file | echo hello
echo world
set -e を使用しましたが、出力は次のとおりです。
$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
world
このシナリオを処理するために、最初の行のsetコマンドに追加オプションとして-opipefailを追加しましょう。
#!/bin/bash
set -eo pipefail
cat non-existing-file | echo hello
echo world
これにより、パイプ内でエラーが発生した場合、失敗した右端のコマンドの終了コードを停止して返す必要があることをBashに通知します。
$ ./hello.sh
hello
cat: non-existing-file: No such file or directory
これにより、前に見たのと同じゼロ以外の終了コードが生成されます。
$ echo $?
1
5. 結論
この記事では、 set -e を使用して、エラーが発生したときにbashスクリプトをすぐに終了させる方法を学びました。 また、 -o pipefail を追加して、パイプが同じように動作するようにすることも学びました。 スクリプトの最初の行として、常に set -eopipefailを追加することをお勧めします。