Help us understand the problem. What is going on with this article?

シェルスクリプトを自己文章化する

More than 1 year has passed since last update.

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

実行例

example.gif

https://asciinema.org/a/SvBn06mWomErMftenqLg0PcxE

全コード

#!/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 の正規表現を変更するとよいでしょう。

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした