「サブディレクトリも含めてファイルを一括処理したいのに、findとループの組み合わせが長くなりすぎる」
「case文でユーザー入力の大文字小文字の揺れに毎回対応しなければならない」
こうした問題は、bashの動作フラグを一行変えるだけで解決できます。
shopt(shell options)コマンドを使うと、globのパターン展開・ゼロヒット時の挙動・文字列比較のルールをスクリプト単位で切り替えられます。コマンドを1つ覚えるだけで、堅牢さが大きく変わります。この記事では、シェルスクリプトの設計に直結するshoptオプションを解説します。globstar(
**でサブディレクトリを再帰)・nullglob(ゼロヒット時に空配列)・nocasematch(大文字小文字を吸収)を中心に、Rocky Linux 9.4 / Ubuntu 24.04 LTSで動作確認した実例で紹介します。この記事のポイント
・shopt -s で有効化、shopt -u で無効化。設定はスクリプト内でのみ有効
・globstar を有効にすると ** でサブディレクトリを再帰処理でき、findの代替になる
・nullglob を有効にするとマッチなし時に空配列になり、globループの誤動作を防げる
・nocasematch を有効にするとcase文・[[ ]]が大文字小文字を区別しなくなる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
shoptコマンドとはなにか|bashの動作スイッチ
bashにはset コマンドや環境変数では設定できない「bash固有の動作フラグ」が40種類以上用意されています。その設定窓口が shopt です。たとえば、デフォルトのbashでは
*.txt のglobにマッチするファイルが0件だった場合、エラーも空配列も返さず、リテラル文字列 *.txt をそのまま引数として渡します。この挙動が原因で「ファイルが存在しないのに処理が走った」というバグが生まれます。shopt -s nullglob 一行で、ゼロヒット時は空配列を返すよう変更できます。shoptの設定はスクリプト内でのみ有効です。スクリプトが終了すれば元の状態に戻るため、システム全体の設定を汚しません。
基本的な使い方|確認・有効化・無効化
1. 現在の設定を確認する
引数なしで実行すると、全オプションとその状態が一覧表示されます。# 全オプションの一覧 shopt # 特定オプションの確認 shopt globstar shopt nullglob
$ shopt globstar globstar off $ shopt nullglob nullglob off $ shopt nocasematch nocasematch off
2. 有効化(-s)と無効化(-u)
# オプションを有効化 shopt -s globstar # オプションを無効化 shopt -u globstar # 有効化後に確認 shopt globstar
$ shopt -s globstar $ shopt globstar globstar on
3. スクリプトの先頭でまとめて設定する
必要なオプションはスクリプトの冒頭にまとめて書くのが設計の基本です。後から有効化すると、それ以前のglobが意図と異なる動きをするリスクがあります。#!/bin/bash set -euo pipefail # shoptの設定はファイルの先頭でまとめて宣言する shopt -s globstar # **でサブディレクトリ再帰 shopt -s nullglob # マッチなし時に空配列 shopt -s nocasematch # 大文字小文字を無視
globstar|**でサブディレクトリを再帰処理する
1. globstarを有効化してファイルを再帰処理する
デフォルトでは** は * と同じ意味を持ちます。shopt -s globstar を設定すると、** が「このディレクトリ以下のすべてのパス」にマッチするようになります。#!/bin/bash shopt -s globstar shopt -s nullglob # /var/log 以下の .log ファイルをすべて処理する for f in /var/log/**/*.log; do echo "Processing: $f" done
Processing: /var/log/audit/audit.log Processing: /var/log/dnf.log Processing: /var/log/dnf.librepo.log Processing: /var/log/dnf.rpm.log Processing: /var/log/httpd/access_log Processing: /var/log/httpd/error_log
2. findとの使い分け設計
globstarとfindは用途で使い分けます。・globstarが適するケース:シンプルな拡張子フィルタ・少ないディレクトリ数・for文で配列として扱いたい場合
・findが適するケース:
-mtime(更新日時)-size(サイズ)-perm(権限)など追加条件が必要な場合条件がシンプルなバッチ処理は globstar の方がコードがすっきりします。複雑な絞り込みが必要な場合は find を選んでください。
3. ディレクトリ自体は除外する
** はファイルだけでなくディレクトリ自体にもマッチします。ファイルのみを処理したい場合は条件分岐で除外します。#!/bin/bash shopt -s globstar nullglob for f in /backup/**/*; do # ディレクトリはスキップ [[ -d "$f" ]] && continue echo "File: $f" done
nullglobとfailglob|ゼロヒット時の安全設計
1. デフォルトの危険な振る舞いを理解する
nullglobが無効(デフォルト)の場合、globにマッチするファイルが0件だとリテラル文字列がそのまま返ります。これが予期しないバグの温床です。# nullglob 無効(デフォルト) # /tmp/work/ にファイルが1件もない場合 for f in /tmp/work/*.csv; do echo "処理: $f" done
処理: /tmp/work/*.csv
/tmp/work/*.csv という文字列が渡ります。削除・移動・変換などの処理を実行するスクリプトでは、これが深刻な誤動作につながります。2. nullglobで安全に処理する
#!/bin/bash shopt -s nullglob files=(/tmp/work/*.csv) echo "対象ファイル数: ${#files[@]}" if [[ ${#files[@]} -eq 0 ]]; then echo "処理対象なし。終了します。" exit 0 fi for f in "${files[@]}"; do echo "処理: $f" done
対象ファイル数: 0 処理対象なし。終了します。
${#files[@]} == 0)になります。事前に件数チェックを入れることで、ゼロ件時の処理を明示的に制御できます。3. failglobでゼロヒットをエラーにする
「対象ファイルが必ず存在しているはずの処理」では、ゼロ件をエラーとして扱う方が安全です。#!/bin/bash shopt -s failglob # マッチなし時はbashがエラーを出す for f in /required/dir/*.conf; do echo "読み込み: $f" done
bash: no match: /required/dir/*.conf
シェルスクリプト講座を見る >>
nocasematch|大文字小文字を区別しないマッチング設計
1. case文での活用
ユーザーの入力や環境変数の値は、大文字小文字の揺れが発生しがちです。nocasematch を有効にすると、case文や [[ ]] での比較が大文字小文字を区別しなくなります。#!/bin/bash shopt -s nocasematch env_type="${1:-production}" case "$env_type" in production) echo "本番環境への適用" ;; staging) echo "ステージング環境への適用" ;; dev*) echo "開発環境への適用" ;; *) echo "不明な環境: $env_type" exit 1 ;; esac
$ bash deploy.sh STAGING ステージング環境への適用 $ bash deploy.sh Staging ステージング環境への適用 $ bash deploy.sh staging ステージング環境への適用
2. [[ ]] の正規表現マッチングへの影響
nocasematch は [[ ]] 内の == パターンマッチと =~ 正規表現マッチにも適用されます。#!/bin/bash shopt -s nocasematch os_info=$(cat /etc/os-release 2>/dev/null | grep '^ID=' | cut -d= -f2 | tr -d '"') if [[ "$os_info" =~ rhel|rocky|almalinux|centos ]]; then echo "Red Hat系: dnf/yum を使用" elif [[ "$os_info" =~ ubuntu|debian ]]; then echo "Debian系: apt を使用" else echo "不明なOS: $os_info" fi
その他の実用的なshoptオプション
1. extglob|拡張glob構文で複雑なパターンを記述する
extglob を有効にすると、@(...)(いずれか1つ)・+(...)(1回以上)・!(...)(否定)などの拡張glob構文が使えます。#!/bin/bash shopt -s extglob nullglob # .log と .err 以外のファイルを処理する for f in /var/log/app/!(*.log|*.err); do echo "対象: $f" done # .sh または .bash で終わるファイルだけを処理 for f in /usr/local/bin/@(*.sh|*.bash); do echo "スクリプト: $f" done
2. dotglob|ドットファイルをglobに含める
デフォルトでは* のglobは .bashrc などのドットファイルにマッチしません。dotglob を有効にすると対象に含まれます。#!/bin/bash shopt -s dotglob nullglob # ホームディレクトリのドットファイルも含めてバックアップ for f in /home/operator/*; do cp "$f" /backup/home/ done
3. cdspell|cd時のスペルミスを自動補正する
対話的なシェルで役立つオプションです。cdspell を有効にすると、cd 時のディレクトリ名のスペルミスを自動修正します。スクリプトより ~/.bashrc での設定が主な用途です。# ~/.bashrc に追記 shopt -s cdspell
トラブルシュート|よくある問題と対処
1. macOS(bash 3.2)でglobstarが使えない
macOSに標準でインストールされているbashはバージョン3.2であり、globstar は bash 4.0以降で追加されたオプションのため使えません。macOS環境でも使いたい場合は Homebrew でbash 5.x をインストールするか、findコマンドで代替してください。# バージョン確認 bash --version
$ bash --version GNU bash, version 5.2.26(1)-release (x86_64-redhat-linux-gnu)
2. サブシェルではshoptの設定が引き継がれない場合がある
(...) で作ったサブシェルは親のshopt設定を引き継ぎますが、bash -c で起動した場合や別スクリプトを bash script.sh で呼び出した場合は引き継がれません。呼び出し先のスクリプトに必要なshoptを再度記述するか、source で読み込んでください。3. nullglobとfailglobの競合
nullglobとfailglobを同時にshopt -s するとfailglobが優先されます。どちらか一方だけを設定してください。設定を間違えたと気づいたら shopt -u failglob で無効化できます。本記事のまとめ
| オプション | 有効化コマンド | 効果・主な用途 |
|---|---|---|
| globstar | shopt -s globstar |
** でサブディレクトリを再帰処理。findの簡易代替 |
| nullglob | shopt -s nullglob |
マッチなし時に空配列を返す。globループの誤動作防止 |
| failglob | shopt -s failglob |
マッチなし時にエラー終了。必須ファイルの存在保証 |
| nocasematch | shopt -s nocasematch |
case文・[[ ]] で大文字小文字を区別しない |
| extglob | shopt -s extglob |
!(...) @(...) 等の拡張glob構文を有効化 |
| dotglob | shopt -s dotglob |
ドットファイルを * globに含める |
| cdspell | shopt -s cdspell |
cd時のスペルミスを自動補正(対話シェル向け) |
シェルスクリプト講座を見る >>
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら
- 前のページへ:シェルスクリプトでgpg暗号化バックアップを自動化する設計|無人実行・エラー処理・復号テストの実装パターン
- この記事の属するカテゴリ:シェルスクリプトへ戻る

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