Open1

shell script を書くうえでの心構え

Shunsuke SuzukiShunsuke Suzuki

導入

個人的にこうあるべきと考える基本的なスタンスです。

ただし、一般的な開発組織において、これに従ってないコードはたくさんあるわけで、それらとどう向き合っていくかは課題です。
理想は徐々に修正していくことが大事ですが、他にもやることはある中でリファクタリングに優先度は上げにくいですし、
シェルスクリプトを頑張って直すより他の言語に移行することを考えたほうがいいんじゃないかとかそういう話もあります。

しかし、それでもあるべき姿の認識を合わせておくことが大事かと思います。

特に新規でシェルスクリプトのファイルを作成する際はこれを意識して書くのが良いと思います。
CI に shellcheck, shfmt を組み込むのが難しい場合でもローカルで実行してみるなどすると良いでしょう。

スタンス

  • shellcheck, shfmt は使う
    • CI に組み込むのが理想
    • shfmt に関連して、インデントは tab か space か揃える(Editorconfig で揃えることもできる)
    • IDE で連携すると逐一実行しなくても気づけて便利
    • shellcheck を通じてシェルスクリプトの罠などを学ぶこともできる
  • シェルスクリプトの先頭で set -euo pipefail を書く
    • ただし、 pipefail は bash の機能なので一部のシェルでは使えない。それでもシェルの種類を意識して書くのは大変なので、基本は bash を使うようにするのが良い
    • 必要に応じて局所的に set +e, set -e を使う
#!/usr/bin/env bash

set -euo pipefail

# ...

# 例えばこういうこと
set +e
terraform plan -detailed-exitcode
code=$?
set -e

# ...
  • shell 関数の利用は計画的に。 shell 関数は使いすぎると複雑度、認知不可が高まり、バグを生む。 shell 関数を多用しなければならなくなったら、それは shell script で書くには複雑になりすぎている可能性が高いので、 Python や Go などの他の言語の利用を検討する
  • シェルスクリプトが複雑になったり肥大化してきたら Python や Go などの他の言語の利用を検討する
  • actionlint を使う (GitHub Actions 限定)
    • actionlint は shellcheck に対応しているので、 run step に対して shellcheck が実行できる