tools
A
信頼度ランク
| S | 公式ソース確認済み |
| A | 成功実績多数・失敗例少数 |
| B | 賛否両論 |
| C | 動作未確認・セキュリティリスク高 |
| Z | 個人所感 |
シェルスクリプト入門:自動化で作業時間を半分にする
Bashスクリプトの基本文法から実践的なユースケースまで解説。ファイル処理の自動化・デプロイスクリプト・定期実行など、すぐに使える自動化パターンを紹介します。
一言結論
シェルスクリプトは冒頭にset -euoを書いてエラーを即時検出し、関数・引数バリデーション・ログ出力の3点を最初から実装することで、「動いているが壊れたら原因不明」なスクリプトを防げる。
なぜシェルスクリプトか
- 追加インストール不要(Bash はほぼ全ての Linux/macOS に標準装備)
- CLIツールをパイプで組み合わせて強力なパイプラインを構築
- cron との組み合わせで定期実行が簡単
- CI/CD の yaml から呼び出せる
基本文法
変数・引数
#!/usr/bin/env bash
set -euo pipefail # エラー時即終了・未定義変数エラー・パイプエラー検知
# 変数
NAME="World"
echo "Hello, ${NAME}!"
# スクリプト引数
# $1 $2 ... → 位置引数
# $# → 引数の数
# $0 → スクリプト名自体
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <filename>" >&2
exit 1
fi
FILE="$1"
条件分岐
# ファイル・ディレクトリの存在確認
if [[ -f "$FILE" ]]; then
echo "ファイルあり"
elif [[ -d "$FILE" ]]; then
echo "ディレクトリあり"
else
echo "存在しない"
fi
# 文字列比較
if [[ "$ENV" == "production" ]]; then
echo "本番環境"
fi
# コマンドの成功/失敗
if git status &>/dev/null; then
echo "Gitリポジトリ内"
fi
ループ
# ファイル一覧をループ
for file in src/**/*.ts; do
echo "処理中: $file"
done
# 配列
ENVS=("dev" "staging" "prod")
for env in "${ENVS[@]}"; do
echo "デプロイ: $env"
done
# 数値ループ
for i in {1..5}; do
echo "試行 $i"
done
関数
# 関数定義
log() {
local level="$1"
shift
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*"
}
log INFO "デプロイ開始"
log ERROR "接続失敗"
実践パターン1: ファイル処理
#!/usr/bin/env bash
# 古いログファイルを圧縮してアーカイブ
set -euo pipefail
LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/backup/logs"
DAYS=30
mkdir -p "$ARCHIVE_DIR"
# 30日以上前のログを探して圧縮
find "$LOG_DIR" -name "*.log" -mtime +$DAYS | while read -r logfile; do
basename=$(basename "$logfile")
gzip -c "$logfile" > "${ARCHIVE_DIR}/${basename}.gz"
rm "$logfile"
log INFO "アーカイブ完了: $basename"
done
log INFO "完了。$(find "$ARCHIVE_DIR" -name '*.gz' | wc -l) ファイルをアーカイブ"
実践パターン2: デプロイスクリプト
#!/usr/bin/env bash
set -euo pipefail
BRANCH="${1:-main}"
DEPLOY_DIR="/var/www/myapp"
BACKUP_DIR="/backup/deploy/$(date +%Y%m%d_%H%M%S)"
log() { echo "[$(date '+%H:%M:%S')] $*"; }
# バックアップ
log "バックアップ中..."
cp -r "$DEPLOY_DIR" "$BACKUP_DIR"
# デプロイ
log "ブランチ $BRANCH をプル..."
cd "$DEPLOY_DIR"
git fetch origin
git checkout "$BRANCH"
git pull origin "$BRANCH"
# ビルド
log "ビルド中..."
npm ci --silent
npm run build
# ヘルスチェック
log "ヘルスチェック..."
sleep 3
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:3000/health)
if [[ "$HTTP_STATUS" != "200" ]]; then
log "ヘルスチェック失敗($HTTP_STATUS)。ロールバック中..."
cp -r "$BACKUP_DIR/." "$DEPLOY_DIR"
exit 1
fi
log "デプロイ成功!"
実践パターン3: 環境セットアップ
#!/usr/bin/env bash
# 新しいマシンの開発環境を一発セットアップ
set -euo pipefail
# コマンドの存在確認
require() {
command -v "$1" &>/dev/null || {
echo "必要なコマンドがありません: $1" >&2
exit 1
}
}
require curl
require git
# Node.js (fnm経由)
if ! command -v fnm &>/dev/null; then
echo "fnm をインストール中..."
curl -fsSL https://fnm.vercel.app/install | bash
export PATH="$HOME/.local/share/fnm:$PATH"
fi
fnm install 22
fnm use 22
# dotfilesのセットアップ
DOTFILES="$HOME/dotfiles"
if [[ ! -d "$DOTFILES" ]]; then
git clone https://github.com/yourname/dotfiles "$DOTFILES"
fi
# シンボリックリンクの作成
CONFIGS=(".bashrc" ".gitconfig" ".tmux.conf")
for config in "${CONFIGS[@]}"; do
ln -sf "$DOTFILES/$config" "$HOME/$config"
done
echo "セットアップ完了!"
よく使うイディオム
# スクリプト自身のディレクトリを取得
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 一時ファイルを作って終了時に削除
TMPFILE=$(mktemp)
trap "rm -f $TMPFILE" EXIT
# コマンドの出力を変数に格納
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
# 並列実行
for task in task1 task2 task3; do
process_task "$task" &
done
wait # 全バックグラウンドプロセスの完了を待つ
# デフォルト値
: "${PORT:=3000}" # PORT が未定義なら 3000
: "${ENV:=development}"
デバッグ
bash -x script.sh # 実行されるコマンドをすべて表示
bash -n script.sh # 構文チェックのみ(実行しない)
# スクリプト内で部分的にデバッグ
set -x # ここからデバッグ出力
# ... 怪しい部分 ...
set +x # デバッグ出力を止める
まとめ
- 必ず先頭に
set -euo pipefailを書く - 変数は常に
"${VAR}"と二重引用符で囲む(スペース対策) - ファイルパスは
find+while readで安全に処理 trapでクリーンアップを必ず実装shellcheckでスクリプトの問題を自動検出
# shellcheck のインストールと使用
sudo apt install shellcheck # Ubuntu/Debian
shellcheck script.sh
参考: Bash リファレンスマニュアル / ShellCheck / Google Shell Style Guide