getopts
| 対応: | 全Linux | |
|---|---|---|
| macOS(2001 Cheetah) | ||
| Bash 1.0(1989) |
『getopts』はシェルスクリプトでコマンドラインオプションを解析するためのビルトインコマンドです。-v や -f filename のような短いオプション(1文字)を while ループと組み合わせて処理します。POSIX 準拠のため、bash・dash・zsh など主要シェルで動作します。
構文
『getopts』の基本構文です。optstring に受け付けるオプション文字を並べ、opt に解析結果が格納されます。
while getopts "optstring" opt; do
case "$opt" in
a) ... ;;
b) ... ;;
esac
done
optstring内の文字の後ろに :(コロン)を付けると、そのオプションが引数を必要とすることを意味します。引数の値は $OPTARG 変数に格納されます。
while getopts "vf:" opt; do
case "$opt" in
v) ... ;; # 引数なし
f) echo "$OPTARG" ;; # -f に続く値が $OPTARG に入る
esac
done
optstring の先頭を : にするとサイレントエラーモードになります。不正なオプションが渡されてもシェルがエラーメッセージを出力しなくなり、スクリプト内で独自のエラー処理を書けます。
while getopts ":vf:" opt; do
case "$opt" in
\?) echo "不正なオプション: -$OPTARG" >&2 ;;
:) echo "-$OPTARG には引数が必要です" >&2 ;;
esac
done
変数一覧
| 変数 | 概要 |
|---|---|
| $OPTARG | 直前に解析したオプションの引数値。-f file.txt の場合は file.txt が入ります。 |
| $OPTIND | 次に解析する引数のインデックス(1始まり)。ループ終了後に shift $((OPTIND - 1)) することで残りの位置引数だけを取り出せます。 |
| $opt(任意名) | 『getopts』が現在解析したオプション文字を格納する変数。名前は自由に付けられます。不正オプション時は ? が入ります。 |
サンプルコード
まず最もシンプルな例で動作を確認します。-v フラグが渡されると verbose モードになります。
cat verbose_check.sh
#!/bin/bash
while getopts "v" opt; do
case "$opt" in
v) echo "verbose モード ON" ;;
esac
done
bash verbose_check.sh -v
verbose モード ON
-f でファイルパス、-v で詳細表示を切り替える例です。引数付きオプション(f:)では $OPTARG に値が格納されます。
dominator_scan.sh
#!/bin/bash
verbose=0
target_file=""
while getopts "vf:" opt; do
case "$opt" in
v) verbose=1 ;;
f) target_file="$OPTARG" ;;
\?) echo "使用法: $0 [-v] [-f ファイル]" >&2; exit 1 ;;
esac
done
if [ "$verbose" -eq 1 ]; then
echo "[VERBOSE] スキャン対象: $target_file"
fi
echo "スキャン開始: $target_file"
実行するコマンドは次の通りです。
bash dominator_scan.sh -v -f suspects.txt [VERBOSE] スキャン対象: suspects.txt スキャン開始: suspects.txt
-v(verbose)、-f(ファイル指定)、-h(ヘルプ)の3オプションと、shift $((OPTIND - 1)) で残りの位置引数を取り出す実用例です。
sibyl_analyzer.sh
#!/bin/bash
verbose=0
report_file=""
usage() {
echo "使用法: $0 [-v] [-f ファイル] [-h] [名前...]"
echo " -v 詳細ログを表示"
echo " -f ファイル 解析対象のレポートファイル"
echo " -h このヘルプを表示"
exit 0
}
while getopts ":vf:h" opt; do
case "$opt" in
v) verbose=1 ;;
f) report_file="$OPTARG" ;;
h) usage ;;
\?) echo "不正なオプション: -$OPTARG" >&2; exit 1 ;;
:) echo "-$OPTARG には引数が必要です" >&2; exit 1 ;;
esac
done
# オプションを消費して残りの位置引数だけにする
shift $((OPTIND - 1))
if [ "$verbose" -eq 1 ]; then
echo "[INFO] レポートファイル: ${report_file:-未指定}"
echo "[INFO] 解析対象: $*"
fi
for name in "$@"; do
echo "シビュラシステムで $name の犯罪係数を解析中..."
done
実行するコマンドは次の通りです。
bash sibyl_analyzer.sh -v -f crime_report.txt "Kogami Shinya" "Tsunemori Akane" [INFO] レポートファイル: crime_report.txt [INFO] 解析対象: Kogami Shinya Tsunemori Akane シビュラシステムで Kogami Shinya の犯罪係数を解析中... シビュラシステムで Tsunemori Akane の犯罪係数を解析中...
概要
『getopts』は呼び出されるたびに1つのオプションを解析し、解析が終わると偽(非0)を返してループを抜けます。$OPTIND は最初 1 で始まり、オプションを1つ処理するたびに進みます。引数付きオプション(-f value)を処理すると $OPTIND は2つ進みます。
ループ終了後に shift $((OPTIND - 1)) を実行することで、$1, $2, ... にオプション以外の残りの引数だけが残ります。"$@" で残りの引数を全て取得できます。
オプションを組み合わせて渡す(-vf file.txt)ことも可能です。『getopts』はまとめて書かれたフラグを1文字ずつ展開して処理します。
よくあるミス
よくあるミス1: optstring 先頭の : の意味
optstring の先頭に : を書くかどうかで、エラー処理の方式が変わります。
| 書き方 | モード | 不正オプション時 | 引数が足りない時 |
|---|---|---|---|
getopts "vf:" opt | 通常モード | シェルがエラー出力 + opt に ? | シェルがエラー出力 + opt に ? |
getopts ":vf:" opt | サイレントモード | opt に ?、$OPTARG に不正文字 | opt に :、$OPTARG にオプション文字 |
通常モードでは不正オプションを渡すと、スクリプト名を含むエラーメッセージがシェルから自動的に標準エラーへ出力されます。サイレントモードではシェルは何も出力せず、case 文の \? と : で独自のエラーメッセージを制御できます。
bash sibyl_analyzer.sh -x ./sibyl_analyzer.sh: illegal option -- x
上記は通常モード(先頭に : なし)の挙動です。サイレントモードなら case "\?") echo "不正なオプション: -$OPTARG" で独自メッセージを出せます。
よくあるミス2: 長いオプション(--verbose)は getopts では扱えない
『getopts』は POSIX 仕様の短いオプション(-v, -f など)しか解析できません。--verbose や --file=path のような長いオプション(GNU スタイル)には対応していません。
bash dominator_scan.sh --verbose ./dominator_scan.sh: illegal option -- -
--verbose は - という不正オプションとして扱われ、エラーになります。長いオプションを扱いたい場合は『getopt』(外部コマンド)または case "$1" in ... esac による手動解析を使います。
case_search.sh
#!/bin/bash
verbose=0
report_file=""
while [ "$#" -gt 0 ]; do
case "$1" in
--verbose) verbose=1; shift ;;
--file) report_file="$2"; shift 2 ;;
--file=*) report_file="${1#--file=}"; shift ;;
--) shift; break ;;
-*) echo "不正なオプション: $1" >&2; exit 1 ;;
*) break ;;
esac
done
echo "verbose: $verbose, file: $report_file"
echo "残りの引数: $*"
修正後は次の通りです。
bash case_search.sh --verbose --file=case_log.txt "Ginoza Nobuchika" verbose: 1, file: case_log.txt 残りの引数: Ginoza Nobuchika
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。