Bash 開発
Bash 5.1+ におけるスクリプト開発のための主要パターンとベストプラクティス。現代的な bash イディオム、エラーハンドリング、引数解析、外部コマンドに代わる純粋 bash による手法を提供します。
スクリプトの基礎
すべてのスクリプトは以下の必須ヘッダーから始めます:
#!/usr/bin/env bash
set -euo pipefail
set オプションの解説:
-e— コマンドが失敗したら即座に終了-u— 未設定の変数をエラーとして扱う-o pipefail— パイプライン内のいずれかのコマンドが失敗したらパイプ全体を失敗させる
スクリプトメタデータパターン
SCRIPT_NAME=$(basename "${BASH_SOURCE[0]}")
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
readonly SCRIPT_VERSION="1.0.0"
readonly SCRIPT_NAME SCRIPT_DIR
エラーハンドリング
堅牢なスクリプトのためのトラップベースのエラーハンドリングを実装します。
引数解析
標準的な引数解析テンプレート。
変数のベストプラクティス
常に中括弧を使い、変数を引用符で囲みます:
# 正しい
"${variable}"
"${array[@]}"
# 誤り
$variable
${array[*]} # 正しいイテレーションのためには [@] を使用
定数には readonly を使用:
readonly CONFIG_FILE="/etc/app/config"
readonly -a VALID_OPTIONS=("opt1" "opt2" "opt3")
注意: ソーススクリプト内では readonly を使用しないでください。再ソース時にエラーの原因となります。
文字列操作(純粋 Bash)
外部ツールよりもネイティブの bash パラメータ展開を推奨します:
# 空白のトリミング
trimmed="${string#"${string%%[![:space:]]*}"}"
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
# 小文字 / 大文字 (Bash 4+)
lower="${string,,}"
upper="${string^^}"
# 部分文字列の抽出
substring="${string:0:10}" # 最初の 10 文字
suffix="${string: -5}" # 最後の 5 文字
# パターンの置換
replaced="${string//old/new}" # すべて置換
replaced="${string/old/new}" # 最初のみ置換
# プレフィックス / サフィックスの除去
no_prefix="${string#prefix}" # 最短マッチ
no_prefix="${string##*/}" # 最長マッチ (basename)
no_suffix="${string%suffix}" # 最短マッチ
no_suffix="${string%%/*}" # 最長マッチ
配列操作
# 宣言
declare -a indexed_array=()
declare -A assoc_array=()
# nullglob を使用した安全なイテレーション
shopt -s nullglob
for file in *.txt; do
process "${file}"
done
shopt -u nullglob
# 配列の長さ
length="${#array[@]}"
# 要素の追加
array+=("new_element")
# インデックス付きイテレーション
for i in "${!array[@]}"; do
printf '%d: %s\n' "${i}" "${array[i]}"
done
ファイル操作
# ファイルを文字列として読み込む
content="$(<"${file}")"
# ファイルを配列に読み込む (Bash 4+)
mapfile -t lines < "${file}"
# ファイルの状態を確認
[[ -f "${file}" ]] # 通常ファイルが存在する
[[ -d "${dir}" ]] # ディレクトリが存在する
[[ -r "${file}" ]] # 読み取り可能
[[ -w "${file}" ]] # 書き込み可能
[[ -x "${file}" ]] # 実行可能
[[ -s "${file}" ]] # 空でない
# 安全なテンポラリファイルの作成
temp_file=$(mktemp)
trap 'rm -f "${temp_file}"' EXIT
条件式
条件分岐には [[ ]] を使用します(bash 固有、より強力):
# 文字列比較
[[ "${var}" == "value" ]] # 等価性
[[ "${var}" == pattern* ]] # グロブマッチング
[[ "${var}" =~ ^regex$ ]] # 正規表現マッチング
# 数値比較
(( num > 10 )) # 算術比較
[[ "${num}" -gt 10 ]] # 従来の構文
# 複合条件
[[ -f "${file}" && -r "${file}" ]]
[[ "${opt}" == "a" || "${opt}" == "b" ]]
ユーティリティ関数
パフォーマンスガイドライン
- 可能な場合は外部コマンドよりも組み込みコマンドを使用する
- 大規模なデータセットではループではなくバッチ処理を行う
- 移植性と制御のために
echoではなくprintfを使用する - タイトループ内での不必要なサブシェルを避ける
- 文字列比較には
[ ]ではなく[[ ]]を使用する
追加リソース
参考ファイル
詳細なパターンと例については:
- bash_example_file.sh — 完全なスクリプトテンプレート
- bash_example_includes.bash — 再利用可能なユーティリティ関数
- bash-agent-notes.md — コンテキストに応じたレビューガイダンス
- pure-bash-bible-strings.md — 文字列操作パターン
- pure-bash-bible-arrays.md — 配列操作
- pure-bash-bible-files.md — ファイル処理パターン
- pure-bash-bible-variables.md — パラメータ展開リファレンス