引数を処理する

引数とは?

引数 (ひきすう) とはコマンド (シェルスクリプト) 実行時に、コマンドラインから渡される値のことである。

引数は実行時にプログラム内で参照され、シェルスクリプトの実行結果 (動作) に影響を与える。引数はパラメータと呼ばれることもある。

command 引数
command 引数1 引数2 … 引数n

→ コマンド名に続けて引数としてコマンドに渡したい値のリストを指定する。

引数はコマンド名に続けてスペース区切りで指定する。引数として指定可能な値の数は各コマンドにより異なる。

【参考】 引数とオプション

コマンド実行時に指定する値には引数とオプションがある。引数は実行に使用されるファイル名や出力されるメッセージなどを指定するのに使用される。

一方、オプションは -f などのように - (ハイフン) とアルファベット1文字で表記され、主にコマンドの振る舞い方を指定する目的で使用されるものである。

また、オプションは -a -l といった複数指定を -al と一つにまとめて指定することもできる。引数に - が含まれる場合には「コマンド名 -- -引数」といったように -- を指定することで、コマンドは -- 以降の -引数 の部分をオプションではなく引数として解釈する。

※ オプションも引数であることには変わりないが、当サイトでは便宜上この 2つを明確に区別することとする。

引数を使用したシェルスクリプト

引数処理に使用する変数

シェルスクリプト実行時に指定された引数は位置パラメータと呼ばれる特殊な変数に自動的に設定される。 シェルスクリプト内からはこの変数を参照することで、引数を処理することが可能になる。 位置パラメータ以外にも、引数の処理に関連した特殊な変数がいくつかあり、 これらを組み合わせて使用することによって柔軟に引数を処理することが可能になる。

変数名 自動的に設定される値
$# 実行時に指定された引数の数を表す変数。$ ./test.sh AAA BBB CCC」と実行された場合、シェルスクリプト test.sh 内で変数 $# を参照するとその値は 3 となる。
$@ シェルスクリプト実行時、もしくは set コマンド実行時に指定された全パラメータが設定される変数。 変数 $* と基本的に同じだが、 "" で囲んだときの動作が異なる。
$* **シェルスクリプト実行時、もしくは set コマンド実行時に指定された全パラメータが設定される変数。**変数 $@ と基本的に同じだが、 "" で囲んだときの動作が異なる。
$0 実行時のコマンド名が設定される変数。./test.sh」と実行した場合には「./test.sh」が、「/home/user/test.sh」と実行した場合には「/home/user/test.sh」が設定される。
$1 - $n シェルスクリプト実行時に指定した引数の値がそれぞれ設定される変数。 1番目に指定した引数は $1 に、2番目に指定した引数は $2 に、n 番目に指定した引数は $n に設定される。10番目以降の引数参照時は ${10} のように {} を使用する必要がある。これは $10$1 "0" のように、シェルに誤った解釈をされることを防ぐためである。

指定された引数の数をチェックする

引数の指定を必要とするするシェルスクリプトを正常に実行するためには、実行時に必要とする数の引数が正確に指定されているかどうかチェックする必要がある。これは実行に引数を必要とするにもかかわらず、引数指定なしで実行された場合に、シェルスクリプトが予期せぬ動作をするおそれがあるためである。

引数が必要な数だけ指定されたかどうかは、変数 $# を参照することで確認することができる。

実際に変数 $# を利用した引数チェックを行うシェルスクリプト (check_param.sh) を作成してみる。このシェルスクリプトは実行に 3つの引数を必要とし、引数が正確に 3つ指定されていない場合はエラー終了する。

#!/bin/bash

# 実行時に指定された引数の数、つまり変数 $# の値が 3 でなければエラー終了。
if [ $# -ne 3 ]; then
  echo "指定された引数は$#個です。" 1>&2
  echo "実行するには3個の引数が必要です。" 1>&2
  exit 1
fi

# ヒアドキュメントでメッセージを表示する。
cat <<__EOT__
指定された引数は、
  $1
  $2
  $3
の$#個です。
__EOT__

exit 0

このシェルスクリプト check_param.sh の実行結果は、以下のとおりとなる。

$ ./check_param.sh
指定された引数は0個です。
実行するには3個の引数が必要です。

$ ./check_param.sh aaa
指定された引数は1個です。
実行するには3個の引数が必要です。
#↑引数が3個指定されていないのでエラー。

$ ./check_param.sh aaa bbb ccc
指定された引数は、
  aaa
  bbb
  ccc
の3個です。
#↑引数を3個指定すると、指定した引数がメッセージと共に表示される。

次は、変数 $0 を利用して Usage メッセージを表示するシェルスクリプト (param_usage.sh) を作成してみる。このシェルスクリプトは実行に 2つの引数を必要とし、実行時の日付と時刻を引数に指定したファイルにそれぞれ保存する。

#!/bin/bash

CMDNAME=`basename $0`
if [ $# -ne 2 ]; then
  echo "Usage: $CMDNAME file1 file2" 1>&2
  exit 1
fi

date '+%D' >$1
date '+%R' >$2

echo "Check created files ..."
ls -l $1 $2

exit 0

変数 $0 はパスを含んでいる可能性があるので basename コマンドを使用し、自分自身のファイル名のみを取得する。$0 が「./param_usage.sh」だった場合、basename コマンドの実行結果は「param_usage.sh」となる。

このシェルスクリプト param_usage.sh の実行結果は、以下のとおりとなる。

$ ./param_usage.sh
Usage: param_usage.sh file1 file2
#↑「./」が取り除かれてファイル名のみが表示されている。

$ /home/sunone/param_usage.sh
Usage: param_usage.sh file1 file2
#↑フルパスで実行してもファイル名のみ表示されている。

$ /home/sunone/param_usage.sh foo bar
Check created files ...
-rw-rw-r-- 1 sunone sunone 6  5月 31 00:22 bar
-rw-rw-r-- 1 sunone sunone 9  5月 31 00:22 foo

オプション解析コマンド getopts を使用する

複雑なオプションの指定を必要とするシェルスクリプトを作成する場合、全てのオプションの妥当性チェック等、パラメータ解析にはかなりの労力を要する。

そのような場合には、オプション解析のためのコマンドである getopts コマンドを使用することで、オプション・パラメータの妥当性チェック処理を容易に作成することが可能となる。

while getopts ab:c: OPT
do
  case $OPT in
    "a" ) FLG_A="TRUE" ;;
    "b" ) FLG_B="TRUE" ; VALUE_B="$OPTARG" ;;
    "c" ) FLG_C="TRUE" ; VALUE_C="$OPTARG" ;;
  esac
done

→ オプション解析には while 文と組み合わせて getopts コマンドを使用する。

getopts コマンドの第一引数にはシェルスクリプトに指定可能なオプションを指定し、さらそのオプションが値を要する場合は : (コロン) を付ける。

つまり、上記の例では「$ command -a -b "BBB" -c "CCC"」といったコマンドラインになる。また、オプションに指定した「“BBB”」や「“CCC”」などの値は変数 OPTARG に自動的に設定される。

第二引数には解析に使用する任意の変数名を指定する。あくまでも変数の名前なので $ を付ける必要はない。

実際に getopts コマンドを利用したシェルスクリプト (param_getopts.sh) を作成してみる。

#!/bin/bash

CMDNAME=`basename $0`

while getopts ab:c: OPT
do
  case $OPT in
    "a" ) FLG_A="TRUE" ;;
    "b" ) FLG_B="TRUE" ; VALUE_B="$OPTARG" ;;
    "c" ) FLG_C="TRUE" ; VALUE_C="$OPTARG" ;;
      * ) echo "Usage: $CMDNAME [-a] [-b VALUE] [-c VALUE]" 1>&2
          exit 1 ;;
  esac
done

if [ "$FLG_A" = "TRUE" ]; then
  echo '"-a"オプションが指定されました。'
fi

if [ "$FLG_B" = "TRUE" ]; then
  echo '"-b"オプションが指定されました。 '
  echo "→値は$VALUE_Bです。"
fi

if [ "$FLG_C" = "TRUE" ]; then
  echo '"-c"オプションが指定されました。 '
  echo "→値は$VALUE_Cです。"
fi

exit 0

このシェルスクリプト param_getopts.sh の実行結果は、以下のとおりとなる。

$ ./param_getopts.sh
#↑オプション指定なしだと何も出力せずに終了する。

$ ./param_getopts.sh -a
"-a"オプションが指定されました。

$ ./param_getopts.sh -a -b "123456"
"-a"オプションが指定されました。
"-b"オプションが指定されました。
→値は123456です。

$ ./param_getopts.sh -ab "123456"
"-a"オプションが指定されました。
"-b"オプションが指定されました。
→値は123456です。
#↑「-ab」のように複数オプションをまとめて指定することも可能。

$ ./param_getopts.sh -a -b "123456" -c
./param_getopts.sh: option requires an argument -- c
Usage: param_getopts.sh [-a] [-b VALUE] [-c VALUE]
#↑「-c」オプションに値が指定されていないのでエラーとなる。

$ ./param_getopts.sh -a -b "123456" -c "ABCDEF"
"-a"オプションが指定されました。
"-b"オプションが指定されました。
→値は123456です。
"-c"オプションが指定されました。
→値はABCDEFです。

shift コマンドでオプション部分を切り捨てる

オプションの他に引数を指定するようなシェルスクリプトの場合、オプション解析終了後に不要となったオプション部分を shift コマンドで切り捨てると以後の引数処理が楽になる。

shift `expr $OPTIND - 1`

→ オプション部分を切り捨てるには、変数 OPTIND から 1 を引いた分だけ shift する。

変数 OPTIND は getopts コマンドがオプションを順番に処理するために使用する、オプション位置を示すカーソルのような働きをする変数である。

getopts コマンド終了後は、この変数の値がオプション部の直後を指し示しているので、この値から 1 引いた分だけ shift することで、オプション部分を切り捨てることができる。

shift コマンドの使用例

$ command -a -b -c "PARAMETER"

上記コマンドラインを実行し、getopts コマンドが、

getopts abc OPT

と指定されている場合、getopts コマンド終了後に変数 OPTIND の値は、“PARAMETER” の位置を指し示している。

その値から 1 を引いて shift するということは、つまり「-c」以前 (-a -b -c) が切り捨てるられるということになる。

実際にオプション部分を切り捨てるシェルスクリプト (param_optind.sh) を作成してみる。

#!/bin/bash

# 「-a」「-b」「-c」オプションを指定可能とする。
while getopts abc OPT
do
  # 解析処理は省略する。
  :
done

# オプション部分を切り捨てる。
shift `expr $OPTIND - 1`

# オプション部分が切り捨てられたので、変数 $1 には先頭の引数が設定されている。
echo "引数に\"$1\"が指定されました。"

exit 0

このシェルスクリプト param_optind.sh の実行結果は、以下のとおりとなる。

$ ./param_optind.sh -abc "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh -ab "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh -ac "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh -a "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh -a -b -c "PARAMETER"
引数に"PARAMETER"が指定されました。

$ ./param_optind.sh -a -b -c "PARAMETER1" "PARAMETER2"
引数に"PARAMETER1"が指定されました。

どんなコマンドラインでも、オプション部分のみが確実に切り取られていることが確認できる。