■ はじめに
https://dk521123.hatenablog.com/entry/2021/08/16/231459
の続き。 先日行ったシェルではエラーハンドリングまで考慮されていなかったので EMR上でStepごとにシェル実行した際に、そのStep内でエラーが発生しても、 途中でキャンセルにならずに、継続されて実行してしまう。 ということで、エラーハンドリングを実装しようと思ったが 思いのほかハマったので、メモしておく。
目次
【1】エラーハンドリングの実装において 1)実装上の注意点 【2】サンプル
【1】エラーハンドリングの実装において
* 以下を参考に行った。 => ただし、以下のサイトの実装(${0} != 0)だけでは不十分。 => 詳細は、「1)実装上の注意点」を参照のこと。
1)実装上の注意点
例えば、ポート番号を間違っていた場合などについては エラーとして返却してくれるが、 存在しないテーブルを指定した場合などについては、 ${0} = 0 で返却されてしまう。
考慮すべき点
* 結論としては、標準エラー出力まで見なくては、 正確なエラーハンドリングにはならない。 ただし、※1について注意。 (この辺は、仕様によって、どこまで考慮するかを決めればいい) => 標準エラーを下記「サンプル」のようにファイル保存している場合は そのファイルを実行前にクリアしておくなどの対応が必要 (「サンプル」だと「trap 'rm -f "$errorlog"' EXIT」部分) => 下記「サンプル」を改めてみると、 標準エラーだけみれば${0}をみる必要ないかもって思った
※1:DROP TABLE IF <table_name>について
* DROP TABLE IF <table_name> 時でも、標準エラーが発生してしまうので注意 => 「IF EXISTS」してんだからエラーに出力しないでくれよ、、、
experiment2.sql
DROP TABLE IF EXISTS :target_table_name;
実行結果
$ ./experiment2.sh Mike 5432 aaa TARGET_USER_NAME = Mike PORT = 5432 TARGET_TABLE_NAME = aaa Result : 0 Error from SQL... <= エラーになってしまう psql:experiment2.sql:1: NOTICE: テーブル"aaa"は存在しません、スキップします
※補足:「set -e」について
なお、この注意点は、 以下の関連記事に記載している「set -e」を付加しても エラーハンドリングできなかった。
https://dk521123.hatenablog.com/entry/2018/03/03/210642
【2】サンプル
https://dk521123.hatenablog.com/entry/2021/08/16/231459
の「【4】の例2」をベースにエラーハンドリングを追加したもの。 => エラーを起こしやすく実験しやすいように 引数「PORT=${2}(ポート番号)」 「TARGET_TABLE_NAME=${3}(テーブル名)」を追加
experimen2.sh
#!/bin/bash # {1} : target user name (e.g. 'Mike') # {2} : Port number (e.g. 5432) # {3} : target table name (e.g. 'user') TARGET_USER_NAME=${1} PORT=${2} TARGET_TABLE_NAME=${3} echo "TARGET_USER_NAME = ${TARGET_USER_NAME}" echo "PORT = ${PORT}" echo "TARGET_TABLE_NAME = ${TARGET_TABLE_NAME}" # Error Handling error_log="./error.log" trap 'rm -f "$errorlog"' EXIT user_count=$(psql -qtAX -h localhost -p ${PORT} -d sample_db -U postgres -f experimen2.sql -v target_name="'${TARGET_USER_NAME}'" -v target_table_name="${TARGET_TABLE_NAME}" 2> "$error_log") if [[ 0 -ne ${?} ]]; then echo "Something went wrong; error log follows:" cat "${error_log}" exit ${?} fi # error file が空じゃない場合、DB内でエラーになっているのでチェック if [[ -s $error_log ]]; then echo "Error from SQL..." cat "${error_log}" exit 1 fi echo "user_count = ${user_count}" # ${user_count} > 0 if [ ${user_count} -gt 0 ]; then echo "OK" exit 0 else echo "ERROR..." exit 1 fi
experimen2.sql
SELECT COUNT(*) AS user_count FROM :target_table_name WHERE user_name=:target_name ;
出力結果
$ ./experimen2.sh Mike 5431 users <= 間違ったポート番号を指定 TARGET_USER_NAME = Mike PORT = 5431 TARGET_TABLE_NAME = users Something went wrong; error log follows: psql: ...: Connection refused (0x0000274D/10061) $ ./experiment2.sh Mike 5432 users <= 正常 TARGET_USER_NAME = Mike PORT = 5432 TARGET_TABLE_NAME = users user_count = 1 OK $ ./experimen2.sh xxxx 5432 users <= 正常だけで検索に引っかからないデータ TARGET_USER_NAME = xxxx PORT = 5432 TARGET_TABLE_NAME = users user_count = 0 ERROR... $ ./experimen2.sh Mike 5432 xxxxx <= 存在しないテーブル名を指定 TARGET_USER_NAME = Mike PORT = 5432 TARGET_TABLE_NAME = xxxx Error from SQL... psql:experimen2.sql:7: ERROR: リレーション"xxxx"は存在しません
関連記事
シェル ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2014/10/23/005406
シェルでSQL結果を受け取る
https://dk521123.hatenablog.com/entry/2021/08/16/231459
psql コマンドでファイル実行した際に引数を渡すには
https://dk521123.hatenablog.com/entry/2021/08/01/000000
psqlでパスワードを省略する
https://dk521123.hatenablog.com/entry/2020/03/06/000000
シェル ~ 基本編・条件分岐 if / case ~
https://dk521123.hatenablog.com/entry/2015/05/01/000043
シェルスクリプトあれこれ
https://dk521123.hatenablog.com/entry/2018/03/03/210642
ファイルへの書き出し
https://dk521123.hatenablog.com/entry/2021/08/14/000000
ヒアドキュメント ~ 複数行の テキストをファイル出力する ~
https://dk521123.hatenablog.com/entry/2016/05/13/231535