Shell インフラ プログラミング

シェルスクリプトで覚えるべきエラーハンドリング一覧

こんにちは!シミダイ(@shimidai2100)です。

シェルスクリプトでバッチツールを開発する時にエラーハンドリングを実施しますが、

何をエラー処理(例外処理)として実装させるかポイントがあります。

今回はシェルスクリプトで覚えるべきエラーハンドリング一覧を紹介したいと思います。

エラーハンドリングのシェルスクリプトサンプルも合わせて載せておきますので参考にしてみてください。

この記事の目的

  • シェルスクリプトでツールやバッチを作成する時に実施しておくべきエラーハンドリング
  • シェルスクリプトのエラーハンドリングのサンプルを紹介

引数の数は一致しているか?

引数の数は一致しているかを確認します。

シェルの引数は「$#」で取得できますで、数の確認を行いましょう。

下が確認方法のサンプルになります。

if [ $# -ne 3 ]; then
  echo "Error argument count."
  exit 1;
fi

上の例では引数が3つ以外の場合エラーとなります。

引数の順番は合っているか?引数が想定された値か?

上の引数の数をエラーチェックをした後に、引数の順番は合っているか引数が想定された値か?を確認します。

渡された引数「$1~$9」をわかりやすい変数に格納しましょう。

下がサンプルになります。

下の例では第1引数で渡された値ファイルなのか?ディレクトリなのか?を確認しています。

#!/bin/sh

INPUTFILE=$1

if [ -d ${INPUTFILE} ]; then
  echo "Error input file name."
  exit 1;
fi

上の例では引数で指定した値がディレクトリならばエラーとなります。

if文で「-f」を指定すると対象がファイルなのかをチェックします。

if文で「-d」を指定すると対象がディレクトリなのかをチェックします。

ファイル・ディレクトリは存在しているか?

ファイルが存在しているか?の存在チェックを行います。

if文では「-e」を利用することでファイルやディレクトリが存在するかチェックを行うことができます。

下がサンプルになります。

#!/bin/sh

INPUTFILE=$1

if [ -e ${INPUTFILE} ]; then
  echo "Error input file name."
  exit 1;
fi

上の例では引数のファイルが存在しない場合エラーとなります。

読み込みファイルのフォーマットは正しいか?

読み込むファイルのフォーマットが正しいか?も重要なチェックになります。

対象のファイルがカンマ区切りのCSVファイルなのか?、環境変数のファイルなのか?を確認するという意味になります。

なお読み込むファイルのフォーマットが正しいかどうか?の確認は、実際にファイルを読み込む直前に行いましょう。

確認とファイル読み込みを別々に行うと余計な処理を行ってしまうためです。

下がサンプルになります。

while read line
do
  cnt=`expr $cnt + 1`
  val01=$(cut -d',' -f 1 <<<${line})
  val02=$(cut -d',' -f 2 <<<${line})
  if [ -z "${val01}" -o -z "${vol02}" ]; then
    echo "val01 is ${val01}.  val02 is ${val02}."
  else
    echo "Error Line ${cnt} : ${line}"
  fi
done < text.csv

上の例では1行読み込み、対象のレコードがカンマ区切られた2つの要素か?を確認しています。

1つでも要素が欠けていたらエラーとします。

所定のディレクトリにファイルを生成できるか?

権限の確認を行うため所定のディレクトリへのファイル生成を行います。

主に結果ファイルやログファイルの生成時に使用します。

私は「touch」コマンドを利用してエラーハンドリングを実施します。

touch ${LOGFILE}

if [ ! -f ${LOGFILE} ]; then
  echo "Error do not create ${LOGFILE}."
  exit 1;
fi

上の例では出力させたログファイルが生成されているか確認しています。

ネストしたシェルや実行コマンドが正常に完了しているか?

ネストしたシェルや実行コマンドが生成した戻り値を確認しましょう。

一般的には戻り値は「0」で正常終了ですが、それ以外の場合もあるので注意が必要です。

私がよく使うやり方は、シェルの戻り値を「$?」で取得してチェック用変数に格納しておく方法です。

ただし「$?」を使うときはパイプ「|」の利用には注意してください。パイプは最後のコマンドの戻り値を利用してしまうからです。

下がサンプルになります。

nested.sh >> ${LOGFILE} 2>&1
ERRCHK=$?

# nested.shのエラー確認
if [ ${ERRCHK} -eq 0 ]; then
  echo "Error!! Check error log."
  exit ${ERRCHK};
fi

上の例では出力させておいたログファイルのtmpファイルを作成し、”ERROR”をgrepで確認しています。

ネストしたシェルや実行コマンドが生成したログに”エラー”や”警告”が出力してないか?

ネストしたシェルや実行コマンドが生成したログに内の情報も必ずチェックするようにしましょう。

戻り値として「0」を返していても、実はエラーとなっている可能性はあります。

私がよく使うやり方は、出力させたログのtmpファイルを作成し、そのtmpファイル内にエラーが出力されていないか?を確認する方法です。

下がサンプルになります。

nested.sh >> ${LOGFILE} 2>&1

# ログファイルをtmpファイルを作成
cp -p ${LOGFILE} ${LOGFILE}.tmp
grep -E "ERROR" ${LOGFILE}.tmp >> ${LOGFILE} 2>&1
ERRCHK=$?

# 実行時に使った不要なファイルは削除
rm -f ${LOGFILE}.tmp

# nested.shのエラー確認
if [ ${ERRCHK} -eq 0 ]; then
  echo "Error!! Check error log."
  exit 1;
fi

上の例では出力させておいたログファイルのtmpファイルを作成し、”ERROR”をgrepで確認しています。

tmpファイルはgrepで確認し終わった後に削除しましょう。

 

本記事のまとめ

  • シェルスクリプトでツール・バッチを作るときは適切なエラーハンドリングする
  • エラーハンドリングは種類が多くあるため一つ一つ覚えよう

随時エラーハンドリングの方法は追記していきます!

 

関連記事

-Shell, インフラ, プログラミング

Copyright© shimidai2100 , 2020 All Rights Reserved.