シェルスクリプト群のドキュメント書くの面倒だから自動でREADME.mdを生成する

タイトルの通りです。

# はじめに

GitHub上で管理しているdotfilesの中に[bin](https://github.com/ssh0/dotfiles/tree/master/bin)なるディレクトリを作って，有象無象のシェルスクリプトを放り込んでいます。

ただ，数が多くなってきて，他の人も見ることを考えたら，このディレクトリにもREADMEを置くべきかもしれないと考えました。

で，しばらくの間は地道に書いていました。

ですが，新しく追加したスクリプトのドキュメントが抜けていたり，削除したスクリプトのドキュメントがREADMEに残ったままになっていたりと，READMEの管理が面倒になってきた。

そこで各ファイルの先頭部分に使い方などをコメントとして書いておいて，そこを抜き出してきてREADMEにまとめられればいいな，と思うわけです。

Pythonならpydocという超絶便利なものがあると知っていたので，同じようなことができないかなーと探していたら，shdocなるものを見つけました。

* [bashful/shdoc at master · jmcantrell/bashful](https://github.com/jmcantrell/bashful/blob/master/bin/shdoc)

```bash
# <doc:shdoc> {{{
#
# Extracts documentation from shell scripts.
#
# Usage: shdoc [OPTIONS] COMMAND [SECTION]
#
# </doc:shdoc> }}}
```

のように，タグで囲んだ部分が出力されるようになるやつらしい。便利そう。

ですが，後学のためにも自分でも実装を考えて書いてみました。

# ファイル中の指定されたコメント領域を抜き出すスクリプト - [header.sh](https://github.com/ssh0/dotfiles/blob/master/bin/header.sh)

* [header.sh](https://github.com/ssh0/dotfiles/blob/master/bin/header.sh)

```bash:header.sh
#!/bin/bash
# written by Shotaro Fujimoto (https://github.com/ssh0)
#=#=#=
# ```
# NAME
#       header.sh - Print the 'header part' of the file.
#
# USAGE
#       header.sh [-h] <file>
#
# REMARK
#       'header part' starts with "#=#=#=" and ends with "#=#="
#       Needs space after each '#'
# ```
#=#=

if [ "$1" = "-h" ]; then
  # print usage
  $0 $0 | grep -v "\`\`\`"
  exit 0
fi

sed -n '/^#=#=#=/,/^#=#=/p' "$1" | sed -e '1d;$d' | cut -b3-
```

sedコマンドを用い、"#=#=#="と"#=#="で囲まれた領域を抜き出します。

例えば、

```bash
#!/bin/bash
# written by me
# 2016/2/3

#=#=#=
# hello_world.sh - The first step of programming.
# 
# Some document is here...
#=#=

# This is comment
echo "Hello World!"

```

のようなファイルがあった時に，

```
header.sh hello_world.sh
```

とすると

```
hello_world.sh - The first step of programming.

Some document is here...
```

と標準出力に出力されます。

これを使えば，READMEを自動生成できそうですね。

# シェルスクリプト群のあるディレクトリでREADME.mdを自動作成するスクリプト - [makebinreadme.sh](https://github.com/ssh0/dotfiles/blob/master/bin/makebinreadme.sh)

* [makebinreadme.sh](https://github.com/ssh0/dotfiles/blob/master/bin/makebinreadme.sh)

```bash:makebinreadme.sh
#!/bin/bash
# written by Shotaro Fujimoto (https://github.com/ssh0)
#=#=#=
# Make bin/README.md
# 
# Required: [header.sh](./header.sh)
#=#=

readme="README.md"

# initialise
cat << EOF > "$readme"
bin
===

Some useful user scripts.

EOF

for file in $(find . -type f -name "*" | sort | grep -v "README"); do
  echo "## ["$(echo ${file##\./} | sed 's@\_@\\_@g')"]($file)" >> "$readme"
  echo >> "$readme"
  echo "$(header.sh "$file")" >> "$readme"
  echo >> "$readme"
done

cat << EOF >> "$readme"
---

This page is generated automatically by [makebinreadme.sh](./makebinreadme.sh)

EOF
```

シェルスクリプトがあるディレクトリで実行すれば，"README"と名のついたもの以外すべてのファイルに対して`header.sh`を実行し，

```markdown
## [hello\_world.sh](./hello_world.sh)

hello_world.sh - The first step of programming.

Some document is here...

```

のように，ファイル名で見出し化+ファイルへのリンクを張った形でREADMEを作成します。

# 現状

結果，自分のbinディレクトリはどうなったかというと，以下のようになっています。

* [dotfiles/bin at master · ssh0/dotfiles](https://github.com/ssh0/dotfiles/tree/master/bin)

また，コメント行に使い方などを書いているのに，同じことをヘルプ関数の中に書くのはナンセンスだ。ということで，いくつかのスクリプトの中では，

```bash:alarm
#!/bin/bash
#=#=#=
# ```
# NAME
#       alarm - Alert after specified time with popup and sound.
# ```
#=#=

f="$0"
usage() {
  sed -n '/^#=#=#=/,/^#=#=/p' $f | sed -e '1d;$d' | cut -b3- | grep -v "\`\`\`"

}
```

のようにして、ヘルプ用の関数を`header.sh`のオプションを短くしたもので置き換えています。"```"で囲っておけば，markdownにした時にコードとして表示されます。

# 終わりに

こういったちょっとした自動化でも，やれば少し楽ができて，勉強もできて，一石二鳥ですね!

もし自分のdotfilesでも使いたいという方は，コードは[WTFPL - Do What the Fuck You Want to Public License](http://www.wtfpl.net/)で公開しているので，ご自由にどうぞ。