自作のシェルスクリプトでオプションに対応させてみた
youmjww.hatenablog.jp
この記事で制作したスラックに通知を送るスクリプトを使っていて、やっぱり場合によってはbotの名前を変えたり、送信するチャンネルやチームを変えたいと思いオプションで指定できる機能を追加してみました。
やってみると結果としては簡単だったけど結構手間取ったので記事にしたいと思います。
プログラム全体を見たい場合は全体のプログラムまで飛んでください。
下準備
とりあえず、失敗したら今まで使っていた環境に戻せるようにしたいのでファイルをコピーかコミットしておいてください。
コミットの場合は人により管理方法が違うと思いますので適当にお願いします。
ここでは仮にslackPostというスクリプトを編集するとします。
コピー
$cp slackPost slackPost.org
全体のプログラム
#!/bin/bash # 送信情報の初期値 acssesToken="<yourSlackAcssesToken>" channelName="random" txt="EndOfProcessing" botName="bot" #引数がある時 if [ $# -ne 0 ]; then #ヘルプの表示 if [ $1 = "-h" ]; then echo "slackPost [option]" echo "-t acssesToken" echo "-c channelName" echo "-b botName" echo "-m messeage" echo "-h help" exit 1 fi #引数の数が正しいか確かめる 正しくなければ処理を終了 checkArgument=$(($# % 2)) if [ $checkArgument = 1 ]; then echo Syntax error exit 0 fi #引数のオプションの処理 args=("$@") for i in `seq 1 $#`; do case ${args[i-1]} in #acssesToken "-t" ) acssesToken=${args[i]};; #channel "-c" ) channelName=${args[i]};; #messeage "-m" ) txt=${args[i]};; #botName "-b" ) botName=${args[i]};; esac done fi #データを作って送信 curl -X POST "https://slack.com/api/chat.postMessage?token=$acssesToken&channel=$channelName&text=$txt&username=$botName" exit 1
解説と定義
オプションの定義
オプションとは、n個の-h
のように-1文字
で構成された文字をオプションとします。
オプションは0 〜 n個指定可能で、オプションの数が変わってもちゃんと動くものとします。
解析方法
オプションの解析は至って簡単で、引数を全て配列にしてあげて、配列に入っているオプションになる文字列を識別してオプションの処理をしてあげるだけです。
ただ、getoptsやgetoptといったオプション解析用のコマンドが用意されているのに何故オプション解析を手動で行うかと言いますと、GNU環境とBSD環境で挙動が変わったり使える使えないがあるみたいで、ubuntuとmacで使いたかったので今回は手動で実装しました。
オプションが指定されていない部分の為に初期値を決めておく
# 送信情報の初期値 acssesToken="<yourSlackAcssesToken>" channelName="random" txt="EndOfProcessing" botName="bot"
ヘルプの表示
-h
が入力されたらヘルプを表示して処理を終了しています。
#ヘルプの表示 if [ $1 = "-h" ]; then echo "slackPost [option]" echo "-t acssesToken" echo "-c channelName" echo "-b botName" echo "-m messeage" echo "-h help" exit 1 fi
引数の数が正しいか調べる
この処理では引数の数を調べて奇数だったらエラーを出力してスクリプトを終了しています。
#引数の数が正しいか確かめる 正しくなければ処理を終了 checkArgument=$(($# % 2)) if [ $checkArgument = 1 ]; then echo Syntax error exit 0 fi
実際の解析
オプションの解析はたったこれだけです。
ここのcase
文はCやJavaでいうところのswitch
文です。
内容は引数を配列にしてオプションの文字を探してオプションにあった処理をしています。
#引数のオプションの処理 args=("$@") for i in `seq 1 $#`; do case ${args[i-1]} in # acssesToken "-t" ) acssesToken=${args[i]};; # channel "-c" ) channelName=${args[i]};; # messeage "-m" ) txt=${args[i]};; # botName "-b" ) botName=${args[i]};; esac done
感想
シェルスクリプトが思ったより難しかったです。
アルゴリズムの部分はすぐに出来たのですが、細かい言語仕様でつまづき時間が結構かかりました。
具体的には、if文の書き方でif [条件式]
だとエラーが出て、not foundとしか言われず、どこがおかしいのかを調べるのに時間かかりました。if文だとif [ 条件式 ]
のように条件式の前後にスペースを入れないといけないんですね。
その他にも、スペースを空けてはいけないところで空けてしまってエラーが出たりバッククォートとシングルクォートを間違えてエラーが出て四苦八苦しましたw
何気にこの規模のシェルスクリプトを書くのは初めてで、すごく時間がかかってしまいましたw