シェルスクリプトを読みやすくする工夫を紹介します
こんにちは ミクシィの 開発本部 SREグループ の riddle です。
※こちらで自己紹介を簡単にしていますのでよろしければご覧ください。
https://mixi-developers.mixi.co.jp/job-change-8c2a7d7c296a
色んな所で使うシェルスクリプトですが非常に便利な反面、他の言語に比べると癖が強く、IDEなどでも対応が少ないため読みづらいと思います。
今回は、そんなシェルスクリプトを書く上で個人的に実践しているいくつかのテクニックを紹介します!
※もっとこうするといいよ!というテクニックをご存知のかたは、ぜひ教えていただけると幸いです
· 1. コマンドオプションは配列を使う
· 2. pipe 中にコメントを挟む
· 3. heredoc の区切りは意味ある文字にする
· 4. 関数を使って処理をまとめる
· まとめ
1. コマンドオプションは配列を使う
例えばこんなコマンドがあるとします。見づらいですね。なんとなくオプションから意味が取れますが、なぜそのオプションが使われているかはわかりません。
$ curl --get --silent --http2 --location -H "Content-Type: application/json" http://google.com
コメントを足してみます。(内容は適当です)
# google.com にアクセスし JSON 形式で結果を取得する
# 301 が帰ってくるので location を指定する
# 高速化のため http2 を使用する
$ curl --get --silent --http2 --location -H "Content-Type: application/json" http://google.com
少しわかりやすくなった気がします。ただ引数が増えてくるとひたすらコメントが長くなりますし、そもそもどのオプションの説明をしているのかわかりません。
ということでおすすめしたいのがこちらです。
$ curl_opt=(
--get
--silent # 高速化のため http2 を使用する
--http2 # 301 が帰ってくるので location を指定する
--location # JSON 形式で出力する
-H "Content-Type: application/json"
)$ curl "${curl_opt[@]}" http://google.com
オプションを配列にまとめ、改行区切りにして定義することで1行に1つのオプションが定義でき、コメントを記載することもできます。
2. pipe 中にコメントを挟む
シェルスクリプトの pipe は非常に便利ですが、時々何をやっているのかがわからなくなるときがあります。このテクニックはそれを少し解消するものです。
こんなコマンドがあるとします。
grep aaa testfile | grep bbbb | sed 's/hoge//g' | awk '{print $2}'
ちょっと整形して見やすくします。
grep aaa testfile \
| grep bbbb \
| sed 's/hoge//g' \
| awk '{print $2}'
さらにこれにコメントを足してみます。
grep aaa testfile \
\
`# testfile 内の bbbb を抽出する` \
| grep bbbb \
\
`# hoge を削除する` \
| sed 's/hoge//g' \
\
`# 2行目のみ取得する` \
| awk '{print $2}'
バッククオート(`)で囲まれた範囲はコマンドとして認識されますが、先頭に(#) がついていればコメントとして扱われるのを利用して`# コメント
`を付与しています。
3. heredoc の区切りは意味ある文字にする
EOF や EOT などが使われる事が多い heredoc ですが、実は結構なんでも使えます。(ためしてみたら * でもイケてビックリ)
cat <<*
aaa
*
aaa
ですので、なんのための heredoc なのかを明示するとよりわかりやすいですね。こんな感じです。
cat << MAIL_TEMPLATE > template.txt
タイトル: xxx
宛先: xxx
本文: xxx
MAIL_TEMPLATE
4. 関数を使って処理をまとめる
例えば、データを取得し、整形して、アップロードするというステップのスクリプトがあったとします。
# データを取得
...
...
...
...
...# データを整形
...
...
...
...
...# データをアップロード
...
...
...
...
...
このように処理の順に書いていくのが通常ですが、処理が増えたり、チェックしたい内容だったりが出てきたときに少し修正しづらいです。
そこで関数を用いてこのようにしてみます。
# データを取得する関数です(xxを引数にとりxxを行います)
function getData() {
...
...
...
...
...
}# データを整形する関数です(xxを引数にとりxxを行います)
function formatData() {
...
...
...
...
...
}# データをアップロードする関数です(xxを引数にとりxxを行います)
function uploadData() {
...
...
...
...
...
}# 処理の実行
getData
formatData
uploadData
関数化により、各関数の役割が明確になりフローもわかりやすくなりました。また関数にしたことで関数単位にチェックやテストを追うことも出来ます。
まとめ
シェルスクリプトは簡単に書けて、手早く、様々なことができる便利なツールですが、こういった観点にも注意してスクリプトを作成してみるとより可読性が上がるかなと思います。
こんなテクニックもあるよ!があれば、ぜひコメントで教えていただけると嬉しいです!