そういう悩みを抱えているサーバー管理者は多いです。
bashスクリプトを書き始めると、最初は位置パラメータ($1、$2…)で引数を受け取ります。しかしスクリプトが育ってきて「-v(詳細表示)」「-o 出力先」「-n(ドライラン)」といったオプションが増えてくると、位置パラメータでの管理はすぐに破綻します。
この記事では、bashの組み込みコマンド
getopts を使ったオプション解析の方法を解説します。基本的な1文字オプションの受け取り方から、引数付きオプション、エラー処理、実務で使えるスクリプト例まで、RHEL 9.4 / Ubuntu 24.04 LTS で動作確認した手順でお伝えします。
この記事のポイント
・getopts は bash 組み込みのオプション解析コマンドで外部コマンド不要
・while getopts "ab:c" opt; do case $opt in で1文字オプションを処理できる
・コロン付き(b:)は引数ありオプション、$OPTARG で値を取得する
・先頭コロン(":ab:")でエラーを自前処理してサイレントモードにできる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
getoptsとは何か、getoptとの違い
getopts は bash の組み込みコマンドです。command -v getopts を実行しても外部ファイルのパスは返らず、getopts is a shell builtin と表示されます。似た名前の
getopt(末尾に s がない)は外部コマンドで、長いオプション(--verbose など)を扱える一方、OS によって挙動が異なり移植性に課題があります。| 比較 | getopts(bash組み込み) | getopt(外部コマンド) |
|---|---|---|
| 長いオプション | 非対応 | 対応(--verbose 等) |
| 移植性 | 高い(POSIX準拠) | OS 差異あり |
| インストール不要 | はい | util-linux パッケージ必要 |
| 実務での用途 | 社内スクリプト・自動化 | 汎用 CLI ツール作成 |
getopts で十分です。getoptsの基本的な書き方
1. オプション文字列の読み方
getopts の第1引数は「オプション文字列」です。# オプション文字列の例 # "abc" → -a -b -c を受け取る(引数なし) # "ab:c" → -a -b 値 -c を受け取る(b は引数あり) # ":ab:c" → 先頭のコロンはサイレントモード(エラー処理を自前で行う)
: が文字の直後に付いている場合、そのオプションは引数を必要とします。先頭に
: が付いている場合は「サイレントモード」となり、エラーメッセージを getopts 自身が出力せず、スクリプト側で制御できます。2. while ループと case 文の組み合わせ
getopts は1回の呼び出しで1つのオプションを処理します。while ループで繰り返し呼び出すのが定石です。#!/bin/bash # 基本的な getopts の書き方 while getopts "vn:o:" opt; do case $opt in v) VERBOSE=true ;; n) NAME="$OPTARG" ;; o) OUTPUT="$OPTARG" ;; \?) echo "不明なオプション: -$OPTARG" >&2 exit 1 ;; esac done # オプション以外の残り引数は $@ に残る shift $((OPTIND - 1)) echo "NAME=$NAME, OUTPUT=$OUTPUT, VERBOSE=$VERBOSE" echo "残り引数: $@"
・$OPTARG:引数ありオプション(コロン付き)で、その引数の値が格納されます
・$OPTIND:次に処理するべき引数のインデックス。
shift $((OPTIND - 1)) で残り引数を $@ に整理できます・\?:未定義のオプションが指定された場合に一致するパターンです
3. 実際に動かす
上記スクリプトをtest-opts.sh として保存して実行します。# 実行権限を付与 $ chmod +x test-opts.sh # オプションを渡して実行 $ ./test-opts.sh -v -n "webserver01" -o /tmp/result.log NAME=webserver01, OUTPUT=/tmp/result.log, VERBOSE=true 残り引数: # 残り引数(ファイル名など)も渡す場合 $ ./test-opts.sh -n "db01" /etc/hosts /etc/hostname NAME=db01, OUTPUT=, VERBOSE= 残り引数: /etc/hosts /etc/hostname
引数ありオプションのエラー処理
1. オプションの引数が省略された場合
コロン付きオプションに引数を与えずに実行すると、getopts はエラーを報告します。# -n オプションの引数を省略した場合(通常モード) $ ./test-opts.sh -n ./test-opts.sh: option requires an argument -- 'n' 不明なオプション: -
#!/bin/bash # サイレントモード(先頭に : を付ける) while getopts ":vn:o:" opt; do case $opt in v) VERBOSE=true ;; n) NAME="$OPTARG" ;; o) OUTPUT="$OPTARG" ;; :) # 引数が必要なオプションに引数が与えられなかった場合 echo "エラー: -$OPTARG には引数が必要です" >&2 exit 1 ;; \?) echo "エラー: 不明なオプション -$OPTARG" >&2 exit 1 ;; esac done
: のパターンが追加されています。このパターンは「引数が必要なオプションに引数が与えられなかった」場合に一致します。2. usageメッセージを関数化する
実務では usage 表示を関数として定義しておくと、複数箇所から呼び出せて便利です。#!/bin/bash usage() { echo "使い方: $0 [-v] [-n ホスト名] [-o 出力先]" >&2 echo "" echo " -v 詳細表示モード" >&2 echo " -n ホスト名 対象ホスト(必須)" >&2 echo " -o 出力先 ログの保存先(デフォルト: /tmp/result.log)" >&2 exit 1 } OUTPUT="/tmp/result.log" # デフォルト値 while getopts ":vn:o:" opt; do case $opt in v) VERBOSE=true ;; n) NAME="$OPTARG" ;; o) OUTPUT="$OPTARG" ;; :) echo "エラー: -$OPTARG には引数が必要です" >&2; usage ;; \?) echo "エラー: 不明なオプション -$OPTARG" >&2; usage ;; esac done # 必須オプションのチェック if [ -z "$NAME" ]; then echo "エラー: -n オプション(ホスト名)は必須です" >&2 usage fi echo "ホスト: $NAME, 出力: $OUTPUT, 詳細: ${VERBOSE:-false}"
実務で使えるスクリプト例
1. サーバー死活確認スクリプト
複数ホストへの ping チェックを行うスクリプトです。オプションでタイムアウトや繰り返し回数を変更できます。#!/bin/bash # check-hosts.sh: サーバー死活確認スクリプト # 使い方: ./check-hosts.sh [-v] [-c 回数] [-t タイムアウト秒] ホスト名 [ホスト名...] COUNT=3 TIMEOUT=5 VERBOSE=false usage() { echo "使い方: $0 [-v] [-c 回数] [-t タイムアウト秒] ホスト名..." >&2 exit 1 } while getopts ":vc:t:" opt; do case $opt in v) VERBOSE=true ;; c) COUNT="$OPTARG" ;; t) TIMEOUT="$OPTARG" ;; :) echo "エラー: -$OPTARG には引数が必要です" >&2; usage ;; \?) echo "エラー: 不明なオプション -$OPTARG" >&2; usage ;; esac done shift $((OPTIND - 1)) # ホスト名がなければエラー if [ $# -eq 0 ]; then echo "エラー: チェック対象のホスト名を指定してください" >&2 usage fi # 各ホストに ping for host in "$@"; do if ping -c "$COUNT" -W "$TIMEOUT" "$host" > /dev/null 2>&1; then echo "[OK] $host は応答しています" if "$VERBOSE"; then ping -c 1 "$host" | grep "time=" fi else echo "[FAIL] $host は応答しません" fi done
# 基本実行 $ ./check-hosts.sh web01.example.local db01.example.local [OK] web01.example.local は応答しています [OK] db01.example.local は応答しています # -v オプションで詳細表示 $ ./check-hosts.sh -v -c 1 web01.example.local [OK] web01.example.local は応答しています 64 bytes from 192.168.10.11: icmp_seq=1 ttl=64 time=0.312 ms # 存在しないホスト $ ./check-hosts.sh -t 2 backup01.example.local [FAIL] backup01.example.local は応答しません
2. ディレクトリ使用量レポートスクリプト
指定ディレクトリ配下の使用量を調べて、しきい値を超えたものを警告します。Linux 基本コマンドの解説で触れているように、du や ls といった基本コマンドをスクリプト化する際に getopts が役立ちます。
#!/bin/bash # disk-report.sh: ディレクトリ使用量レポート # 使い方: ./disk-report.sh [-d 検索ディレクトリ] [-s しきい値MB] [-v] TARGET_DIR="/var" THRESHOLD=500 VERBOSE=false while getopts ":d:s:v" opt; do case $opt in d) TARGET_DIR="$OPTARG" ;; s) THRESHOLD="$OPTARG" ;; v) VERBOSE=true ;; :) echo "エラー: -$OPTARG には引数が必要です" >&2; exit 1 ;; \?) echo "エラー: 不明なオプション -$OPTARG" >&2; exit 1 ;; esac done echo "=== ディスク使用量レポート ===" echo "対象: $TARGET_DIR / しきい値: ${THRESHOLD}MB" echo "" # しきい値(MB)を超えるディレクトリを表示 du -mx "$TARGET_DIR" --max-depth=2 2>/dev/null \ | awk -v threshold="$THRESHOLD" '$1 > threshold {print $0}' \ | sort -rn \ | while read size path; do echo "[警告] ${size}MB $path" done if "$VERBOSE"; then echo "" echo "--- 上位10件(全体) ---" du -mx "$TARGET_DIR" --max-depth=2 2>/dev/null | sort -rn | head -10 fi
getoptsで陥りやすいトラブルと対処法
1. shift $((OPTIND - 1)) を忘れた場合
getopts はオプションを処理しても $1 以降の引数を自動でシフトしません。shift $((OPTIND - 1)) を忘れると、while ループ後でも $@ にオプション文字が残ったままになります。# OPTIND を確認する $ cat debug-opts.sh #!/bin/bash while getopts "vn:" opt; do case $opt in v) echo "OPTIND=$OPTIND, opt=$opt" ;; n) echo "OPTIND=$OPTIND, opt=$opt, OPTARG=$OPTARG" ;; esac done echo "shift 前: $@" shift $((OPTIND - 1)) echo "shift 後: $@" $ ./debug-opts.sh -v -n server01 file1.txt file2.txt OPTIND=2, opt=v OPTIND=4, opt=n, OPTARG=server01 shift 前: -v -n server01 file1.txt file2.txt shift 後: file1.txt file2.txt
2. オプション引数にハイフンから始まる値を渡してしまう
-n -verbose のように渡すと、getopts は -verbose をオプションとして解釈しようとしてエラーになります。引数の値がハイフンから始まる可能性がある場合は、
-n="-verbose" や --(オプション終了マーカー)を使う回避策を検討してください。3. 関数の中で getopts を使う場合の注意
関数内でgetopts を呼ぶ場合、$OPTIND はグローバル変数のため、関数入口で local OPTIND=1 と宣言することで意図しない動作を防げます。# 関数内で getopts を使う正しい書き方 parse_options() { local OPTIND=1 # ★ 必須:関数内でリセット local opt while getopts "vn:" opt; do case $opt in v) echo "verbose mode" ;; n) echo "name=$OPTARG" ;; esac done } parse_options -v -n test01 parse_options -n server02
4. 「option requires an argument」が出るパターン
コロン付きオプションに引数を与え忘れた場合に発生します。Linux ポート確認の全コマンドのように、スクリプトでポート番号をオプション引数で受け取る場合は、数値バリデーションも合わせて実装しておくと安全です。
# ポート番号のバリデーション例 while getopts ":p:" opt; do case $opt in p) if ! [[ "$OPTARG" =~ ^[0-9]+$ ]] || [ "$OPTARG" -lt 1 ] || [ "$OPTARG" -gt 65535 ]; then echo "エラー: ポート番号は 1~65535 の整数で指定してください" >&2 exit 1 fi PORT="$OPTARG" ;; :) echo "エラー: -$OPTARG には引数が必要です" >&2; exit 1 ;; \?) echo "エラー: 不明なオプション -$OPTARG" >&2; exit 1 ;; esac done echo "指定ポート: $PORT"
本記事のまとめ
| やりたいこと | 書き方 |
|---|---|
| 引数なしオプション(-v)を受け取る | while getopts "v" opt; do case $opt in v) … |
| 引数ありオプション(-n 値)を受け取る | while getopts "n:" opt、値は $OPTARG |
| 不明なオプションを処理する | case の \?) パターンで処理 |
| 引数省略エラーを自前処理する | 先頭コロン ":n:" + case の :) パターン |
| オプション処理後に残り引数を取り出す | shift $((OPTIND - 1)) |
| 関数内で getopts を使う | 関数の冒頭で local OPTIND=1 を宣言 |
getopts を覚えると、「とりあえず動く一回きりのスクリプト」から「オプションで柔軟に動作を変えられる再利用可能なスクリプト」へ一段階昇格できます。コロンの付け方と
$OPTARG・$OPTIND の役割さえ把握すれば、使いこなすのは難しくありません。まずは手元のスクリプトで
$1・$2 による引数受け取りを getopts に書き換えてみてください。シェルスクリプトのメンテナビリティが一気に上がります。
ls コマンドの基本オプションやcsh 環境変数設定の解説のような基本コマンドを組み合わせて、本格的なシェルスクリプトを書いていきましょう。
「スクリプトが書けるLinuxエンジニア」になりたいなら
getopts を使いこなせると、メンテナブルな自動化スクリプトが書けるようになります。
ネットの古い情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 次のページへ:trapコマンドでbashスクリプトのシグナルを捕捉・処理する方法|一時ファイル削除やエラー終了処理の実践例も
- 前のページへ:sarコマンドでシステムパフォーマンスを時系列で確認する方法|CPU・メモリ・ディスク統計の読み方と活用も
- この記事の属するカテゴリ:Linuxtips・シェルスクリプトへ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます