表題のことで少しハマったので、その反省文です。
元tweet
bash力が足らなくて仕事が詰まってる…😖
— T.MOTOOKA (@t_motooka) 2023年3月14日
(対話型では上手く動くのに、shell script に書くと動かなくなるタイプのトラブル)(守秘義務範囲のものを排除した再現手順とかを構築できたら反省文を公開します)
落ちるスクリプトと、その実行結果
#!/bin/bash set -e set -u set -x TODAY=$(date +%Y-%m-%d) read -r -d '' MESSAGE <<EOF 今日は ${TODAY} です。 これは2行目のテキストです。 EOF echo "done" echo "$MESSAGE"
このスクリプトを保存して動かすと、以下のような出力があり、終了ステータス1で終了します。エラーメッセージは特に何もありません。
++ date +%Y-%m-%d + TODAY=2023-03-14 + read -r -d '' MESSAGE
これらの出力は、 set -x
による効果で、実行しているコマンドのログです。
このログから、read
コマンドは実行されているのに、最後の2つのechoコマンドは実行されていないことがわかります。
なぜ落ちるのか?
read
コマンドは、EOFにより読み込みを終了した場合は、exit status が0ではありません。
linuxcommand.org
手元の環境では1だったのですが、 set -e
オプションが指定されている状況においては、これはスクリプトを終了させる原因になります。
落ちないスクリプト
read
コマンドの実行時だけ、エラー時即時終了オプション set -e
を解除すれば、とりあえずの解決になります。
例
#!/bin/bash set -e set -u set -x TODAY=$(date +%Y-%m-%d) set +e read -r -d '' MESSAGE <<EOF 今日は ${TODAY} です。 これは2行目のテキストです。 EOF set -e echo "done" echo "$MESSAGE"
set -e のご加護が無い時の注意
エラー時即時終了というのは、多くの場合でとても有益であり、間違いに素早く気付くキッカケになります。このご加護をoffにするということは、エラーに気付きにくくなるということです。
heredocを書いている途中でよくあるエラーと言えば、展開する変数のスペルを間違うことだと思いますが、これは set -u
が効いて、きちんと落ちてくれます。
他のエラーの例がぱっと思いつかなかったのですが、この解決策を適用する際は「-eのご加護が無い」ということを肝に銘じておきましょう。
どうやってこの原因究明を成し遂げたのか?
AskUbuntuの回答についたコメントを見ることで気付きました。自力では解決できませんでした(反省)
stackoverflow.com