Interpret argument with bash
bashシェルスクリプトで引数を解釈し処理するスクリプトを書きたい時に必要になるコマンドや特殊変数、関数をまとめました。例もあるよ。
※ $@について追記しました!感謝! https://twitter.com/masutaka/status/796703261185216512
$*
順番に見てく。まず$*。
すべての引数が設定される特殊変数。
こんなスクリプトがあったとして…。
#!/bin/sh
echo $*
こうなる。
$ ./argument.sh a bb ccc
a bb ccc
$@
すべての引数が設定される特殊変数。え!?@*と同じじゃん!
違いは、「$@はスペース区切りで設定される」のに対し、「@*は環境変数IFS区切りで設定される」こと!知らなかった...。
IFSが空の場合は上にもあるようにスペース区切り。
$ ./argument.sh a bb ccc
a bb ccc
環境変数IFSを設定すると...。
#!/bin/sh
IFS='区切りだよ'
echo $*
おお...。おもろい。
$ ./argument.sh abbccc
abbccc
$ ./argument.sh a区切りだよbb区切りだよccc
a bb ccc
ちなみにIFSはInternal Field Separatorの略!
内部フィールド区切り文字 (Internal Field Separator) です。展開を行った後に単語を分割する場合や、組み込みコマンドの read を使ったときに行を単語に分割する場合に使われます。 デフォルト値は "<空白><タブ><改行>" です。
https://linuxjm.osdn.jp/html/GNU_bash/man1/bash.1.html
getopt
コマンドラインオプションを解釈するコマンド。
getopt 解析するオプション 解析される引数のように書く- 解析される引数に
$*とすればスクリプトに渡した引数が解析対象となるので便利
- 解析される引数に
- オプションに
:をつけると、そのオプションは引数必須になる ab:c:のように書いた場合期待されるオプションは-a,-b 引数,-c 引数となる- 無効なオプションが渡された場合はexitステータス1を返す
- getoptコマンド(コマンドラインのオプションを解析する) : JP1/Advanced Shell
- Man page of GETOPT
動きを見てく。
#!/bin/sh
getopt ab:c: $*
echo exit status is $?
-aは引数無くてOK。
$ ./getopt.sh -a
-a --
exit status is 0
あってもOK。
$ ./getopt.sh -a hoge
-a -- hoge
exit status is 0
-bは引数必須!
$ ./getopt.sh -b
getopt: option requires an argument -- b
--
exit status is 1
$ ./getopt.sh -b hoge
-b hoge --
exit status is 0
複数のオプション。
$ ./getopt.sh -a -b hoge
-a -b hoge --
exit status is 0
$ ./getopt.sh -a -b hoge -c fuga
-a -b hoge -c fuga --
exit status is 0
set
オプションを設定するコマンド。オプション無しで引数を渡して実行した場合、引数は順番に位置パラメータ変数($1,$2,$3,...)に格納される。
#!/bin/sh
args=$(getopt ab:c: $*)
set $args
echo \$1 : $1
echo \$2 : $2
echo \$3 : $3
echo \$4 : $4
echo \$5 : $5
この例だと-a,-bはsetコマンドのオプションとして解釈されてしまっているので位置パラメータに保存されていない。
$ ./setopt.sh -a -b hoge -c fuga
$1 : hoge
$2 : -c
$3 : fuga
$4 : --
$5 :
--
--以降はオプションではないということを明示するオプション
$ cat setopt.sh
#!/bin/sh
args=$(getopt ab:c: $*)
set -- $args
echo \$1 : $1
echo \$2 : $2
echo \$3 : $3
echo \$4 : $4
echo \$5 : $5
-a,-bがオプション扱いされなくなった
$ ./setopt.sh -a -b hoge -c fuga
$1 : -a
$2 : -b
$3 : hoge
$4 : -c
$5 : fuga
$#
引数の数が格納されている特殊変数。
$ cat setopt.sh
#!/bin/sh
args=$(getopt ab:c: $*)
set -- $args
echo \$1 : $1
echo \$2 : $2
echo \$3 : $3
echo \$4 : $4
echo \$5 : $5
echo \$6 : $6
echo \$7 : $7
echo \$# is $#
こんな感じ。
$ ./setopt.sh -a -b hoge -c fuga
$1 : -a
$2 : -b
$3 : hoge
$4 : -c
$5 : fuga
$6 : --
$7 :
$# is 6
shift
位置パラメータの名前を変えるコマンド。
shift 2で$3の位置パラメータが$3マイナス2のようにずれていく。
$ cat shiftopt.sh
#!/bin/sh
args=$(getopt ab:c: $*)
set -- $args
shift 2
echo \$1 : $1
echo \$2 : $2
echo \$3 : $3
echo \$4 : $4
echo \$5 : $5
echo \$6 : $6
echo \$7 : $7
echo \$# is $#
2つ位置パラメータをずらしたことによって-aと-bが消えた。
$ ./shiftopt.sh -a -b hoge -c fuga
$1 : hoge
$2 : -c
$3 : fuga
$4 : --
$5 :
$6 :
$7 :
$# is 4
while
条件満たすまで繰り返し処理。
例は無し!
case
特定の条件の時所定の動作させる。
例は無し!
[]と[[]]
見た目にてるけど別物![]より[[]]のほうが2倍強い(?)。
[はtestコマンドで]は[の必須の引数- こういう既に存在する構文に別の記法を与えたものを「シンタックスシュガー」という
[[は複合コマンド(?)の1つでシェルの構文(testコマンドではない)- 違いは、
[[]]は中で&&とかできる。[]はtestコマンドなので&&みたいなtestコマンドにない挙動は出来ない
渡したオプションと引数を表示するシェルスクリプト
オプションや特殊変数について見てきました。その集大成として、渡したオプションを表示するシェルスクリプトを書いてみます。
- whileで位置パラメータの数がゼロになるまで処理を繰り返す
- caseでgetoptで指定したオプションにマッチさせechoする
- caseせのマッチ処理実行後shiftで位置パラメータをずらし、処理済みのマッチさせたパラメータを消す
- 引数付きのオプションはオプションと引数で2つ分の位置パラメータを有しているので2つずらしている
--(getoptが自動的に最後にくっつけるオプション)が来たらshitしてcaseを抜ける
#!/bin/sh
args=$(getopt ab:c: $*)
set -- $args
while [[ $# -gt 0 ]]; do
case $1 in
-a) echo option is $1
shift 1;;
-b) echo option -b\'s argument is $2
shift 2;;
-c) echo option -c\'s argument is $2
shift 2;;
--) shift
break;;
esac
done
実行。
$ ./showopt.sh -a -b hoge -c fuga
option is -a
option -b's argument is hoge
option -c's argument is fuga
$ ./showopt.sh -a -c fuga
option is -a
option -c's argument is fuga
$ ./showopt.sh -b hoge -c fuga -x
getopt: illegal option -- x
option -b's argument is hoge
option -c's argument is fuga
やったぜ。
かんそう
シェルスクリプトでオプションや引数を処理するのはけっこう大変...。シェルはプログラミング言語ではないので、独特な書き方になるのですね。
おまけ
シェルスクリプトでデフォルト値有りの変数を定義するやり方。
:
何もしないコマンド。何もしないけどコマンドなので: > hoge.txtのように引数を渡せる。
${parameter:=word}
bashパラメータ。指定がない場合、wordがデフォルトの値としてparameterに入る。ほかにも幾つか種類がある。
見てく。 以下のようなスクリプトを用意。
#!/bin/sh
echo ${MY_PARAMETER:='is default parameter'}
こんな感じで何もしないとデフォルトのis default parameter が表示される。MY_PARAMETER変数に値を入れておくと、その値が使われる。
$ ./param.sh
is default parameter
$ export MY_PARAMETER='is specified parameter'
$ ./param.sh
is specified parameter
なんか既視感がと思ったらこの話は既に書いていた!
: ${parameter:=word}
行頭に「:」が入ってます。
- シェルスクリプトでparameterを変数の初期化で使いたい場合(上の例のようにechoしたりコマンドの引数として使わない時)、そのまま
${parameter:=word}と書くとwordがコマンドと解釈されてしまう - そこで
:コマンドの引数として書けばデフォルトの値設定ができる
:コマンド使わないとis default parameterがコマンド扱いになる。
見てく。スクリプト用意。
#!/bin/sh
${MY_PARAMETER:='is default parameter'}
echo $MY_PARAMETER
実行。
$ ./param.sh
./param.sh: line 3: is default parameter: command not found
is default parameter
そこで、何もしない:コマンドを使うことでis default parameterをデフォルト値持ちの変数として定義出来る!
$ cat param.sh
#!/bin/sh
: ${MY_PARAMETER:='is default parameter'}
echo $MY_PARAMETER
$ ./param.sh
is default parameter