はじめに
みなさん、こんにちは。torihaziです。
本日は タイトル通り オプション付きのシェルスクリプトを作成してみました。
作成したきっかけは本業で近しいものを作ったからです。
業務効率化の目的です。
それでは行ってみましょう!!
コード
#!/bin/sh #全ての引数 args="$*" #$*でコマンドライン引数全てを取得します。 #出力先(デフォルト) output=output.txt while [[ $# > 0 ]]; do # $#で与えた引数の数を取得します。 case $1 in -h) echo "" echo "Usage: sh $0 -i input_file -n name [-o output]" #$0で実行スクリプト名を取得します。 echo "" exit 0 ;; -i) shift # shift で引数をずらす事ができます。 # -f でファイルならtrue、 =~で正規表現で判別ができます。$1は1番目の引数です # ! をつけると 否定となります。 # そのため1番目の引数が ファイルでかつ先頭に - がないならtrue となります。 if [[ -f $1 && ! $1 =~ ^- ]];then input=$1 else echo "読み込み可能なファイルを指定してください" echo "詳しくは -h を指定してください" exit 1 fi ;; -n) shift # -n で 文字数があればtrueなので $1の文字数がありかつ先頭に - がないならtrueとなります。 if [[ -n $1 && ! $1 =~ ^- ]];then name=$1 else echo "名前を指定してください" echo "詳しくは -h を指定してください" exit 1 fi ;; -o) shift if [[ -n $1 && ! $1 =~ ^- ]];then output=$1 else echo "出力先を指定してください" echo "詳しくは -h オプションを指定してください" exit 1 fi ;; esac shift done # 最後に必須オプションを指定します。 # はじめに判別をかけてもいいのですが、なんとなく後ろにしました。 if [[ ! "$args" =~ -i || ! "$args" =~ -n ]];then echo "必須オプションが未指定です。" echo "詳しくは -h オプションを指定してください" exit 1 fi echo $input,$name,$output
そもそもオプション付きのスクリプトとは?
どういうものかというと
sh option.sh -i input_file -n name [-o output_file]
とかの -i input_file
とか -o output_file
とかいうものです。
もちろんinput_fileや output_fileとして渡してあげても動くことは動きます。
ただ、ぱっと見分かりにくいですよね。何をしてくれるのかは分かりません。
sh convertText.sh hoge.txt hoge1.txt
テキストをConvertしてくれるシェルスクリプトだから何かを変えるスクリプトかな?
この引数に渡しているファイルはなんだろう。。
のように製作者以外が中身を見なければわからないものになってしまいます。
さらにみた人がスクリプトに対して知識がない人だともうギブアップです。
そのような問題を可能な限り解決するためにこれらのオプションを付与することは有効です。
例えば -i で 何かをinputするとか -o で何かを outputする というのは
なんとなく想像がつきます。
他の目的としたら製作者自身の自己満足になります
解説
一番掴みづらいのは shift
だと思います。
shiftを使うと引数を 1つずらす事ができます。
例えば
sh option.sh -i test.txt -n name -o output.txt
としたとき
- $1 : -i
- $2: test.txt
- $3: -n
- $4: name
- $5: -o
- $6: output.txt
としても取得する事自体は可能です。
ではこの後に追加で -u や -t オプションが追加されたらどうなりますか。
if 文の分岐が増えるし、やっぱ -i いらないやってなった時
コードの変更をしなくてはならないので改修が面倒です。
この問題を解決してくれるのが引数ずらしのshift
です。
これをするとどうなるのか。
コードを見ながら順に追っていくと
sh option.sh -i test.txt -n name -o output.txt
この状態で実行されると プログラムは次のように認識します。
- $1 : -i
- $2: test.txt
- $3: -n
- $4: name
- $5: -o
- $6: output.txt
引数は 6個なので $# = 6となります。($# > 0を満たします。)
ではそのままwhileに入ります。
最初にcase文で$1 を判別します。
今回は $1=-i
であるので
-i) shift if [[ -f $1 && ! $1 =~ ^- ]];then input=$1 else echo "読み込み可能なファイルを指定してください" echo "詳しくは -h を指定してください" exit 1 fi ;;
の処理が該当します。
そして 入るとすぐにshift
がありますね。
すると先ほどの引数の先頭が削れてこうなります。
- $1: test.txt
- $2: -n
- $3: name
- $4: -o
- $5: output.txt
最初に合った -i
が削れて $1が1つ上にシフトされました。
そうなるとこのshift
以降は$1=test.txt
となるので
$1=test.txt
として以降が処理されます。
今回は あらかじめtest.txtというファイルを作成しているため
if文がtrueとなり、 inputという変数にそのまま$1が代入されます。
そしてcaseを出た後にまたshift
がありますね。
するとどうなるか。
- $1: -n
- $2: name
- $3: -o
- $4: output.txt
となります。
あとはこれを引数がなくなるまで whileで繰り返すだけになります。
という仕組みを使うことによってオプション付きのスクリプトを作成する事ができます。
例えば -m monthとして 月を指定したり、-d day として 日を指定できたら
日付をデータとして扱うようなスクリプトも作れてしまうかもしれません。
単純な shスクリプトですが、侮る事無かれです。
終わりに
いかがだったでしょうか。
人にしては大した事ないし、もしかしたらこれ使う?という代物かもしれません。
ですが、こういうものに興味があればぜひ色々作ってみてください。
必ず知識が身についてどこかで役に立つかもしれませんよ。
余談ですが私は2年前まで Dドライブすら知らない未経験者でした。
そんな僕でもできたので皆さんなら余裕です。
大丈夫です。一緒に頑張りましょう。僕も頑張ります。