Friday I/O
株式会社ワムウでは、毎週金曜日は 興味がある事柄に取り組み、その成果を何らかの形でアウトプットする日 としています。
はじめに
Dockerを使用した開発では docke-run
, docker-compose run
のようなコマンドと引数の数が複雑になりがちです。
そのために皆さん都度ラッパースクリプトを記述し解決を図ることでしょう。
しかし時間が経った後に、そのスクリプトを走らせようとした時はしばしばラッパースクリプトのサブコマンドを忘れていたりするものです。
Usage
を丁寧に記述することで、この問題は解決することにはなりますが Usageを都度メンテナンスする必要がある という別の問題が発生します。
これらの問題を解決するために シェルスクリプトを自己文章化する という解決策を提示します。
実現方法
下記のように Usage
をファイルの先頭にまとめて記述するのではなく、各サブコマンド関数名の後ろに ##
を付けてコメントを記述します。
version() ## Show version
{
echo "$(basename ${0}) version 0.0.1 "
}
start() ## Start some program
{
echo "COMMAND START"
}
stop() ## Stop some program
{
echo "COMMAND STOP"
}
restart() ## Stop and Restart
{
stop && start
}
このようなサブコマンドが記述されたスクリプトに、Usageをこのように記述します。
usage() ## Show this message
{
echo '\033[33mUsage:\033[m'
echo " $0 [command]"
echo
echo '\033[33mCommands:\033[m'
grep -E '^(function\s+)?\w+\(\)\s+\{?\s*##' $0 | sed -e 's/{//;s/ \{1,\}/ /g;s/function //;s/() ## /<>/' | awk -F '<>' '{printf " \033[36m%-20s\033[0m %s\n", $1, $2}'
}
後は各関数を引数として受け取りサブコマンド化するだけです。
ACTION="$1"
if [ -n "$(type -t $ACTION)" ] && [ "$(type -t $ACTION)" = function ]; then
$ACTION $@
else
echo "\033[31m[ERROR] Invalid command \033[m'${1}'"
echo
usage
exit 1
fi
実行例
全コード
#!/bin/sh
ACTION="$1"
version() ## Show version
{
echo "$(basename ${0}) version 0.0.1 "
}
start() ## Start some program
{
echo "COMMAND START"
}
stop() ## Stop some program
{
echo "COMMAND STOP"
}
restart() ## Stop and Restart
{
stop && start
}
usage() ## Show this message
{
echo '\033[33mUsage:\033[m'
echo " $0 [command]"
echo
echo '\033[33mCommands:\033[m'
grep -E '^(function\s+)?\w+\(\)\s+\{?\s*##' $0 | sed -e 's/{//;s/ \{1,\}/ /g;s/function //;s/() ## /<>/' | awk -F '<>' '{printf " \033[36m%-20s\033[0m %s\n", $1, $2}'
}
if [ -n "$(type -t $ACTION)" ] && [ "$(type -t $ACTION)" = function ]; then
$ACTION $@
else
echo "\033[31m[ERROR] Invalid command \033[m'${1}'"
echo
usage
exit 1
fi
サブコマンドを case
文で処理したい場合などは grep
の正規表現を変更するとよいでしょう。