実践的Bash開発ツールセット:パラメータ解析からカラー出力まで

Bashスクリプトの品質向上に役立つ実用的な開発ツールを紹介する。引数の可視化、ターミナル出力の装飾、コマンドラインオプションの解析という3つの課題に対し、実戦で検証されたソリューションを解説する。

引数デバッガ:シェルパラメータの可視化

スクリプト間で引数が正しく渡されているか確認する際、単なるecho "$@"では位置情報や境界処理が分かりにくい。以下のツールは引数を順序付きで色分け表示し、開発効率を大幅に向上させる。

実装コード

#!/usr/bin/env bash
set -eEuo pipefail

calcDigits() {
  local n=$1 len=0
  while ((n != 0)); do
    ((++len))
    ((n /= 10))
  done
  echo "$len"
}

total=$#
pad=$(calcDigits $total)

readonly C_RED='\e[1;31m' C_CYAN='\e[1;36m' C_OFF='\e[0m'

outputArg() {
  local pos=$1 val=$2
  if [[ -t 1 ]]; then
    printf "%${pad}d/%d: ${C_RED}[${C_CYAN}%s${C_RED}]${C_OFF}\n" "$pos" "$total" "$val"
  else
    printf "%${pad}d/%d: [%s]\n" "$pos" "$total" "$val"
  fi
}

outputArg 0 "$0"
i=1
for v; do
  outputArg $((i++)) "$v"
done

動作確認例

$ ./arg-debug.sh "file 1.txt" 'single' $'multi\nline' *.sh
0/4: [./arg-debug.sh]
1/4: [file 1.txt]
2/4: [single]
3/4: [multi
line]
4/4: [deploy.sh]

応用パターン

関数の入出力検証に組み込む例:

verifyParams() {
  local func=$1
  shift
  [[ "${TRACE:-}" == "1" ]] && {
    echo "=== $func ==="
    /path/to/arg-debug.sh "$@"
  }
  "$func" "$@"
}

ターミナルカラー制御ライブラリ

ANSIエスケープシーケンスを安全に扱うためのラッパー関数群。パイプ出力時の自動無効化や、複合スタイルの簡潔な指定を実現する。

コア関数

cPrint() {
  local style=$1; shift
  [[ -t 1 ]] && printf '\e[%sm%s\e[0m\n' "$style" "$*" || printf '%s\n' "$*"
}

cPrintNoLF() {
  local style=$1; shift
  [[ -t 1 ]] && printf '\e[%sm%s\e[0m' "$style" "$*" || printf '%s' "$*"
}

スタイル指定表

コード効果用途
0;30黒文字補助情報
1;31赤太字エラー表示
1;32緑太字成功通知
1;33黄太字警告
0;34青文字リンク・パス
0;35マゼンタ強調
0;36シアン進行状況
0;37;41白字赤背景重大エラー
0;30;43黒字黄背景注意喚起

状態連動出力例

statusOut() {
  local code=$1 msg=$2
  case $code in
    0) cPrint "1;32" "✓ $msg" ;;
    1) cPrint "1;31" "✗ $msg" ;;
    2) cPrint "1;33" "⚠ $msg" ;;
    *) cPrint "0;36" "ℹ $msg" ;;
  esac
}

# 使用例
statusOut $? "バックアップ処理"

拡張オプションパーサ

従来のgetoptsgetoptの制限を克服し、長形式オプション・複数値引数・厳密な検証を統合した解析エンジン。

構文定義

モード文字列でオプションの振る舞いを指定する:

# パターン: 短名,長名[:モード]
# モードなし: 真偽値
# :         : 単一値必須
# +         : 複数値(配列)

"q,quiet|o,output:|I,include+"
# → -q / --quiet      : フラグ
# → -o / --output     : 単一値
# → -I / --include    : 複数値

利用例

#!/usr/bin/env bash
source "./lib/optParser.sh"

optParser "v,verbose|d,depth:|p,path+" "$@"

[[ "${_OPT_FLAG_verbose}" == "true" ]] && set -x

[[ -n "${_OPT_VAL_depth}" ]] && {
  echo "検索深度: ${_OPT_VAL_depth}"
}

((${#_OPT_ARR_path[@]} > 0)) && {
  echo "検索パス: ${_OPT_ARR_path[*]}"
}

echo "その他の引数: ${_OPT_REST[*]}"

実行サンプル

$ ./finder.sh -v --depth 3 --path /home --path /var --name "*.log"
検索深度: 3
検索パス: /home /var
その他の引数: --name *.log

エラーハンドリング

終了コード状況
221無効なオプション定義(予約文字使用など)
230不正なオプション形式(---optなど)
231必須値の欠落
optParser "f,file:" "$@" || {
  echo "引数解析エラー (コード: $?)" >&2
  exit 1
}

堅牢性を高める実行モード

本ツールセット全体で採用しているset -eEuo pipefailの効果と対処法を解説する。

各オプションの役割

-e (errexit)
コマンドが非ゼロ終了時に即座に終了。失敗の連鎖を防ぐ。
-E (errtrace)
ERRトラップをサブシェル・関数に継承。一貫したエラー捕捉を保証。
-u (nounset)
未設定変数の参照を即座にエラー。タイポによる予期せぬ動作を防止。
-o pipefail
パイプライン全体で失敗を検出。最終コマンドのみの成功に依存しない。

未設定変数への対処

# デフォルト値の付与
: "${WORK_DIR:=/tmp/work}"

# 必須チェック(未設定時はメッセージ付き終了)
: "${API_KEY:?API_KEY環境変数が必要です}"

# 空文字列と未設定の区別が必要な場合
: "${DEPLOY_TARGET:?}"  # 空でも設定されていれば通過

一時的な緩和

特定のコマンドで許容が必要な場合:

# コマンド単位で無効化
grep pattern file || true

# サブシェルで局所的に変更
result=$(set +e; may_fail_command; echo $?)

クリーンアップ保証

cleanup() {
  [[ -d "${TEMP_DIR:-}" ]] && rm -rf "$TEMP_DIR"
}

trap cleanup EXIT INT TERM ERR

統合活用パターン

3つのツールを組み合わせた実用的なスクリプト構成:

#!/usr/bin/env bash
set -eEuo pipefail

# ツール読み込み
SCRIPT_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
source "${SCRIPT_ROOT}/lib/optParser.sh"
source "${SCRIPT_ROOT}/lib/colorLib.sh"

# オプション解析
optParser "c,config:|v,verbose|h,help" "$@" || {
  cPrint "1;31" "引数エラー"; exit 1
}

[[ "${_OPT_FLAG_help}" == "true" ]] && { showHelp; exit 0; }

# 設定検証
: "${_OPT_VAL_config:?設定ファイルを -c で指定してください}"

# デバッグモード
[[ "${_OPT_FLAG_verbose}" == "true" ]] && {
  cPrint "0;36" "実行パラメータ:"
  "${SCRIPT_ROOT}/tools/arg-debug.sh" "$@"
}

# メイン処理
cPrintNoLF "0;36" "処理中... "
processData "${_OPT_VAL_config}"
cPrint "1;32" "完了"

# 後片付け
trap '' EXIT  # 正常終了時はクリーンアップ不要

これらのツールは個別に利用可能であり、既存のスクリプトに段階的に導入できる設計となっている。

タグ: bash Shell Script CLI ANSI Escape Argument Parsing

8月26日 16:15 投稿