Bashのfor文・if文入門|ファイル操作自動化

Bashスクリプトは、LinuxやmacOsのシステム管理や日常的なファイル処理を効率化するうえで欠かせないツールです。しかし、初心者の方にとって「ループ制御」と「条件分岐」は理解しづらい概念だと言われています。本記事では、Bashのfor文とif文の基本から実践的なファイル操作の自動化まで、段階的に解説します。正しくマスターすれば、手作業で30分かかるファイル処理が、わずか数秒で完了するようになります。約7分で読めます。

【目次】

  • 1. Bashスクリプトの前提知識
  • 2. if文の基本構文と条件判定
  • 3. for文でループ処理を自動化
  • 4. 実践例:複数ファイルの自動処理
  • 5. よくある失敗パターンと対処法
  • 6. よくある質問(FAQ)
  • 7. まとめ

1. Bashスクリプトの前提知識

Bashとは何か

Bash(Bourne Again Shell)は、Unix系OSに標準搭載されたコマンドシェルです。Linux、macOS、Windows WSL環境など、ほぼすべてのサーバー環境で利用できるとされています。Bashスクリプトとは、複数のシェルコマンドをファイルに記述し、一括実行するための仕組みです。

スクリプト実行の第一歩

Bashスクリプトを作成する流れは以下の通りです。

  • テキストエディタで .sh 拡張子ファイルを作成
  • 1行目に #!/bin/bash と記述(シェバング行)
  • chmod +x script.sh で実行権限を付与
  • ./script.sh で実行

例えば以下のようなスクリプトを作成すれば、すぐに実行できます。

#!/bin/bash
echo "Hello, Bash!"

このスクリプトを実行すると、ターミナルに「Hello, Bash!」と表示されます。この基本的な構造を理解することが、if文やfor文を学ぶための第一歩となります。

2. if文の基本構文と条件判定

if文の構造

Bashのif文は、指定した条件が真(true)か偽(false)かを判定し、異なる処理を実行するための制御構文です。基本的な形は以下の通りです。

if [ 条件 ]; then
    # 条件が真の場合の処理
fi

注意点として、[] の前後には必ずスペースが必要だとされています。また、fi でif文を閉じることを忘れないようにしましょう。

比較演算子と条件判定

Bashで利用できる主要な比較演算子を表形式でまとめました。

演算子説明使用例
-eq数値が等しい[ $num -eq 5 ]
-ne数値が等しくない[ $num -ne 5 ]
-lt数値が小さい[ $num -lt 10 ]
-gt数値が大きい[ $num -gt 0 ]
-fファイルが存在する[ -f /path/to/file ]
-dディレクトリが存在する[ -d /path/to/dir ]
=文字列が等しい[ “$str” = “test” ]
!=文字列が等しくない[ “$str” != “test” ]

else・elif の使い方

条件によって異なる複数の処理を実行する場合、elseelif を用いることができます。

#!/bin/bash
age=25

if [ $age -lt 18 ]; then
    echo "未成年です"
elif [ $age -lt 65 ]; then
    echo "働き盛りです"
else
    echo "定年後の年齢です"
fi

このスクリプトを実行すると、「働き盛りです」と表示されます。elif は複数個つなげることも可能で、複雑な条件判定に対応できるとされています。

ファイル・ディレクトリの存在確認

ファイル操作の自動化で特に重要な確認方法が、ファイルやディレクトリが実際に存在するかの判定です。

#!/bin/bash
file="/home/user/data.txt"

if [ -f "$file" ]; then
    echo "ファイルが存在します"
    cat "$file"
else
    echo "ファイルが見つかりません"
fi

このスクリプトにより、ファイルが存在する場合のみその内容を表示し、存在しない場合はエラーメッセージを出力することができます。変数を二重引用符で囲むことは、ファイル名に空白が含まれている場合の対応としても推奨されています。

3. for文でループ処理を自動化

for文の基本形

Bashのfor文は、リストの各要素に対して同じ処理を繰り返すための構文です。

for 変数 in リスト; do
    # 繰り返す処理
done

例えば、複数のファイル名をループで処理する場合は以下のようになります。

#!/bin/bash
for file in *.txt; do
    echo "処理中: $file"
done

このスクリプトを実行すると、カレントディレクトリのすべての .txt ファイルに対してメッセージを表示します。*.txt はワイルドカード展開と呼ばれ、マッチするファイルが自動的にリストに変換されるとされています。

数値ループの実装

特定の回数だけ処理を繰り返す場合、C言語風のfor文を使うことができます。

#!/bin/bash
for (( i=1; i<=5; i++ )); do
    echo "ループ回数: $i"
done

このスクリプトは1から5までをカウントアップし、各回数をターミナルに表示します。ループカウンタ i を使うため、繰り返し回数に応じた処理が可能になります。

配列を使った高度なループ

複数の値を一度に処理したい場合、配列を活用することができます。

#!/bin/bash
files=("report.txt" "data.csv" "log.txt")

for file in "${files[@]}"; do
    echo "処理対象: $file"
done

配列の各要素には通常の変数と同じようにアクセスでき、${配列名[@]} とすることですべての要素をループ対象にできるとされています。

4. 実践例:複数ファイルの自動処理

例1. ログファイルの自動バックアップ

サーバー管理の現場では、定期的にログファイルをバックアップするニーズがあります。以下のスクリプトは、指定ディレクトリのすべてのログファイルをバックアップディレクトリにコピーします。

#!/bin/bash
log_dir="/var/log"
backup_dir="/backup/logs/$(date +%Y%m%d)"

if [ ! -d "$backup_dir" ]; then
    mkdir -p "$backup_dir"
    echo "バックアップディレクトリを作成しました: $backup_dir"
fi

for logfile in "$log_dir"/*.log; do
    if [ -f "$logfile" ]; then
        cp "$logfile" "$backup_dir/"
        echo "バックアップ完了: $(basename $logfile)"
    fi
done

echo "全ログファイルのバックアップが完了しました"

このスクリプトのポイントは以下の通りです。

  • $(date +%Y%m%d) で現在日時を8桁の数字に変換し、ファイル名に含める
  • [ ! -d "$backup_dir" ] で負の条件判定(存在しない場合)を使用
  • mkdir -p で親ディレクトリを自動作成
  • 各ファイルの確認と処理を行い、完了メッセージを出力

例2. テキストファイルの一括編集

複数のテキストファイル内にある特定の文字列を置換したい場合の処理例です。

#!/bin/bash
target_dir="/data/documents"
old_text="OLD_VALUE"
new_text="NEW_VALUE"

for file in "$target_dir"/*.txt; do
    if [ -f "$file" ]; then
        if grep -q "$old_text" "$file"; then
            sed -i.bak "s/$old_text/$new_text/g" "$file"
            echo "置換完了: $(basename $file)"
        fi
    fi
done

このスクリプトの処理フロー:

  • grep -q で対象ファイルに置換対象の文字列が含まれるか確認(-q は出力なしオプション)
  • sed -i.bak で元ファイルを直接編集しながら、元ファイルの .bak バックアップを作成
  • 置換が実行された場合のみメッセージを表示

例3. 特定の条件に合うファイルのクリーンアップ

古いファイルや特定のサイズ以上のファイルを自動削除するシナリオは、クラウド環境でのストレージ最適化に有効だとされています。

#!/bin/bash
target_dir="/tmp/cache"
retention_days=7

for file in "$target_dir"/*; do
    if [ -f "$file" ]; then
        mod_time=$(stat -f %m "$file" 2>/dev/null || stat -c %Y "$file" 2>/dev/null)
        current_time=$(date +%s)
        age_days=$(( (current_time - mod_time) / 86400 ))

        if [ $age_days -gt $retention_days ]; then
            rm "$file"
            echo "削除: $(basename $file) (経過日数: $age_days日)"
        fi
    fi
done

注記:ファイル削除はシステムに大きな影響を与える操作のため、本番環境での実行前に自己責任において十分なテスト環境で動作確認を行うことが強く推奨されています。

5. よくある失敗パターンと対処法

エラー1. スペースの不足

Bashの条件式では括弧や演算子の周囲のスペースが必須だとされています。

# ❌ 間違い
if[$age -gt 18]; then

# ✅ 正解
if [ $age -gt 18 ]; then

エラー2. 変数名の間違い

ループ内の変数スコープミスは頻出エラーです。

#!/bin/bash
for file in *.txt; do
    count=$(wc -l < "$file")
done

echo $count  # ループ後の最後のファイルのカウント値が保持される

ループ終了後も変数は値を保持するため、意図しない値が参照される可能性があるとされています。

エラー3. ファイル名にスペースが含まれる場合の処理失敗

ファイル名に空白が含まれる場合、正しい処理のためにはダブルクォートで囲む必要があります。

#!/bin/bash
# ❌ スペース含みファイルで失敗
for file in *.txt; do
    cat $file  # スペイスがあると分割されてしまう

# ✅ 正解
for file in *.txt; do
    cat "$file"
done

エラー4. コマンド実行結果の参照ミス

バッククォートや$(...) で囲まれたコマンド置換の結果を正しく使用していない例です。

#!/bin/bash
for file in *.log; do
    size = $(stat -f%z "$file")  # ❌ スペースが入っている
    size=$(stat -f%z "$file")    # ✅ 正解
done

6. よくある質問(FAQ)

Q1. whileループはfor文とどう違うのですか?

A. for文は「リストの各要素に対して」処理を繰り返す構文であるのに対し、while文は「指定した条件が真である間」処理を繰り返す構文だとされています。ファイル処理では通常for文を使いますが、ユーザー入力待機など条件ベースの繰り返しではwhile文が適しています。

Q2. 深くネストされた条件式はどう処理すればいいですか?

A. && (AND)|| (OR) を使って複数条件を組み合わせることができます。例えば if [ -f "$file" ] && [ -r "$file" ]; then のように複数の条件を一行で判定できます。可読性が下がる場合は、条件を複数のif文に分けることも有効だとされています。

Q3. for文で「現在のループ番号」を知るには?

A. C言語風のfor文 for (( i=0; i<${#array[@]}; i++ )) を使用すれば、ループカウンタ i でインデックスを参照できます。または配列インデックスを${配列名[$i]} で直接アクセスする方法もあります。

Q4. スクリプト実行時に「Permission denied」エラーが出ます

A. ファイルに実行権限がないことが原因だとされています。chmod +x script.sh で実行権限を付与してください。また、相対パス(./script.sh)で実行することも重要です。

Q5. ファイル処理で予期しないエラーが発生した場合、どう対処しますか?

A. スクリプト冒頭に set -e を記述すると、エラー発生時にスクリプト全体が停止するとされています。また set -u で未定義変数の使用を防ぎ、set -x でデバッグ情報を表示できます。本番運用ではエラーハンドリングと実行ログの記録が重要な実装となります。

7. まとめ

Bashのif文とfor文は、ファイル操作の自動化に欠かせない制御構文です。本記事で解説した内容をまとめます。

【if文の要点】

  • 括弧と演算子の前後にはスペースが必須
  • ファイル存在確認(-f)やディレクトリ確認(-d)が頻出パターン
  • else、elifで複数の条件分岐が可能
  • ファイル名に空白が含まれる場合はダブルクォートで囲む

【for文の要点】

  • ワイルドカード(*.txt)でマッチするファイルをループ可能
  • C言語風for文で数値ループを実装
  • 配列と組み合わせて複数値の処理に対応
  • ループ内の変数はループ終了後も値を保持

【実装時の注意点】

  • ファイル削除などの破壊的操作はテスト環境で十分確認
  • エラーハンドリング(set -e等)の導入
  • 本番運用ではログ記録とバックアップを実装
  • ファイル名の空白や特殊文字への対応

これらの知識を組み合わせれば、日々の単調なファイル処理を効率的に自動化できるようになります。特にサーバー管理やデータ処理の現場では、数十分の手作業を数秒に短縮することが可能だとされています。基本的な構文理解の後は、実務で頻出するシナリオ(ログ整理、設定ファイル編集、ストレージ管理)への適用を段階的に進めることが、スキル習得の近道となるでしょう。

【編集・制作ポリシー】
本記事はRoute Bloom編集部が各ベンダー公式ドキュメント・エンジニア監修をもとに作成しています。インフラ・クラウド構築は環境により異なります。本番環境への適用前に必ずテストを実施してください。情報の正確性には万全を期していますが、最新情報は各公式ドキュメントをご確認ください。
ABOUT ME
たから
サラリーマンをしながら開業して経営やってます。 今年、本業で独立・別事業を起業予定です。 ◆経験:IT講師/インフラエンジニア/PM/マネジメント/採用/運用・保守・構築・設計 ◆取得資格:CCNA/CCNP/LPIC-1/AZ-900/FE/サーティファイC言語 ◆サイドビジネス:アパレル事業/複数のWEBメディアを運営