言語
日本語
English

Caution

お使いのブラウザはJavaScriptが無効になっております。
当サイトでは検索などの処理にJavaScriptを使用しています。
より快適にご利用頂くため、JavaScriptを有効にしたうえで当サイトを閲覧することをお勧めいたします。

  1. トップページ
  2. シェルスクリプト辞典
  3. for

for

対応: for 変数 in リスト POSIX(sh互換)
C言語風 for (( )) Bash(bash拡張)

『シェルスクリプト』の for 文は、リストやシーケンスの各要素に対して同じ処理を繰り返す構文です。for 変数 in リスト 形式で要素を1つずつ取り出す書き方が基本で、bash ではさらに C 言語風の for ((i=0; i<n; i++)) 形式も使えます。コマンド置換($(コマンド))と組み合わせればコマンドの出力をそのままリストとして扱え、ファイルグロブと組み合わせればディレクトリ内のファイルを一括処理できます。

基本構文

for ループは do でブロックを開始し、done で閉じます。in の後に列挙した値・変数・コマンド置換の結果が1つずつ変数に代入されて繰り返されます。

キーワード意味説明
forループの開始ループ変数とリストを宣言します。
inリストの指定反復対象となる値の一覧を記述します。省略すると $@(引数全体)を使います。
do処理ブロックの開始繰り返す処理をここから書き始めます。
done処理ブロックの終了ループを閉じます(do を逆から読んだ語です)。
breakループの中断現在の for ループを即座に抜けます。
continue次の反復へスキップ以降の処理をスキップして次の要素の処理に進みます。
# for 文の基本的な書き方(for...in 形式)
for 変数 in 値1 値2 値3; do
    # 変数 に 値1 → 値2 → 値3 の順に代入されて実行されます
    処理
done

# C 言語風の数値カウント(bash 専用)
for ((i=0; i<n; i++)); do
    処理
done

# ブレース展開でシーケンスを作る(bash 専用)
for i in {1..5}; do
    処理
done

# コマンド置換でコマンドの出力を反復します
for 変数 in $(コマンド); do
    処理
done

# グロブでファイルを反復します
for file in /path/to/*.txt; do
    処理
done

for...in リスト形式

in の後に空白区切りで値を並べるか、配列を展開して使います。配列全体を展開するときは "${配列名[@]}" と記述してください。ダブルクォートで囲まないと、スペースを含む要素が単語分割されてしまいます。

書き方説明
for x in a b c値を直接列挙します。スペース区切りでリストを指定します。
for x in "${arr[@]}"配列の全要素を安全に展開します。スペースを含む要素も1つとして扱われます。
for x in "${arr[*]}"配列を1つの文字列として展開します。IFS の区切り文字でつながれるため通常は [@] を使います。
for x in {1..10}1 から 10 までの整数シーケンスを展開します(bash 専用)。
for x in {0..9..2}0 から 9 まで 2 ステップずつ展開します(bash 専用、ステップ指定)。

C 言語風 for 形式(bash 専用)

for ((初期化; 条件; 更新)) 形式は bash 専用の算術 for ループです。インデックスを使った繰り返しや、カウンタを制御したい場合に便利です。sh では使えないため、移植性が必要なスクリプトでは while ループで代替してください。

部分説明
初期化ループ開始前に1度だけ実行されます。カウンタ変数の初期値を設定します。
条件各反復の前に評価されます。0(真)の間ループを続けます。
更新各反復の後に実行されます。カウンタのインクリメントなどを記述します。
# C 言語風の基本的な書き方
for ((i=0; i<5; i++)); do
    echo "i = ${i}"
done

# デクリメント(カウントダウン)
for ((i=5; i>0; i--)); do
    echo "カウントダウン: ${i}"
done

# ステップを 2 ずつ増やす
for ((i=0; i<=10; i+=2)); do
    echo "偶数: ${i}"
done

コマンド置換との組み合わせ

$(コマンド) の出力を for のリストとして使えます。seq コマンドや lsfindcat の出力をそのまま反復できるため、外部コマンドと組み合わせた柔軟な処理が書けます。ただし、スペースや改行を含むファイル名を扱う場合はグロブ展開のほうが安全です。

よく使う組み合わせ説明
for i in $(seq 1 10)seq コマンドで 1〜10 の数値リストを生成します。sh でも動作します。
for line in $(cat file.txt)ファイルの各行を反復します。スペースを含む行は分割されるため注意が必要です。
for f in $(find . -name "*.log")find の結果を反復します。スペースを含むパスには対応できません。
for host in $(cat hosts.txt)ホストリストファイルの各行を反復します。SSH 一括処理などに使います。

ファイル一覧の反復処理

ディレクトリ内のファイルを処理するには、コマンド置換よりグロブ展開*.txt など)のほうが安全です。グロブはシェルが展開するため、スペースを含むファイル名にも対応できます。ファイルが1件もない場合の対策として nullglob オプション(bash)を使う方法もあります。

書き方説明
for f in /dir/*.txt指定ディレクトリの .txt ファイルを反復します。
for f in ./*カレントディレクトリの全ファイル・ディレクトリを反復します。
for f in /dir/**/*.log再帰的にサブディレクトリを含めて反復します(bash の globstar オプションが必要です)。
shopt -s nullglobマッチするファイルが0件のときグロブをそのまま文字列として扱わず展開しないようにします。

サンプルコード

yakuza_for_in.sh
#!/bin/bash
# -----------------------------------------------
#  龍が如くシリーズのキャラクターで
#  for...in リスト形式の使い方を確認します
# -----------------------------------------------

# -----------------------------------------------
#  キャラクター名を配列に格納します
# -----------------------------------------------

characters=("桐生一馬" "真島吾朗" "秋山駿" "冴島大河" "錦山彰")

echo "=== 龍が如く キャラクター一覧 ==="
echo ""

# for...in で配列の全要素を反復します
# "${配列[@]}" と必ずダブルクォートで囲んでください
# スペースを含む名前でも1要素として正しく扱われます
for chara in "${characters[@]}"; do
    echo "  - ${chara}"
done

echo ""
echo "=== 番号付きで表示します ==="
echo ""

# インデックス付きで表示するには C 言語風 for を使います
for ((i=0; i<${#characters[@]}; i++)); do
    # ${#配列[@]} で配列の要素数を取得します
    echo "  ${i}: ${characters[$i]}"
done

echo ""
echo "キャラクター数: ${#characters[@]} 人"
$ chmod +x yakuza_for_in.sh
$ ./yakuza_for_in.sh
=== 龍が如く キャラクター一覧 ===

  - 桐生一馬
  - 真島吾朗
  - 秋山駿
  - 冴島大河
  - 錦山彰

=== 番号付きで表示します ===

  0: 桐生一馬
  1: 真島吾朗
  2: 秋山駿
  3: 冴島大河
  4: 錦山彰

キャラクター数: 5 人
yakuza_c_style_for.sh
#!/bin/bash
# -----------------------------------------------
#  龍が如くシリーズのキャラクターで
#  C 言語風 for ループの使い方を確認します
# -----------------------------------------------

# -----------------------------------------------
#  キャラクターの戦闘力スコアを配列に格納します
# -----------------------------------------------

names=("桐生一馬" "真島吾朗" "秋山駿" "冴島大河" "錦山彰")
scores=(9800 9500 8200 9100 8700)

echo "=== 戦闘力ランキング(C 言語風 for) ==="
echo ""

# C 言語風 for でインデックスを制御します
# i=0 から配列の要素数未満まで 1 ずつ増やします
for ((i=0; i<${#names[@]}; i++)); do
    name="${names[$i]}"
    score="${scores[$i]}"
    printf "  %d位  %-16s  スコア: %d\n" "$((i + 1))" "${name}" "${score}"
done

echo ""
echo "=== カウントダウン(デクリメント) ==="
echo ""

# i を 5 から 1 まで 1 ずつ減らします
for ((i=${#names[@]}; i>=1; i--)); do
    echo "  第${i}位: ${names[$((i - 1))]}"
done

echo ""
echo "=== 偶数インデックスのキャラクターだけ表示します ==="
echo ""

# ステップを 2 ずつ増やして偶数インデックスのみ取り出します
for ((i=0; i<${#names[@]}; i+=2)); do
    echo "  ${names[$i]}(インデックス ${i})"
done
$ chmod +x yakuza_c_style_for.sh
$ ./yakuza_c_style_for.sh
=== 戦闘力ランキング(C 言語風 for) ===

  1位  桐生一馬          スコア: 9800
  2位  真島吾朗          スコア: 9500
  3位  冴島大河          スコア: 9100
  4位  錦山彰            スコア: 8700
  5位  秋山駿            スコア: 8200

=== カウントダウン(デクリメント) ===

  第5位: 錦山彰
  第4位: 冴島大河
  第3位: 秋山駿
  第2位: 真島吾朗
  第1位: 桐生一馬

=== 偶数インデックスのキャラクターだけ表示します ===

  桐生一馬(インデックス 0)
  秋山駿(インデックス 2)
  錦山彰(インデックス 4)
yakuza_cmd_sub_for.sh
#!/bin/bash
# -----------------------------------------------
#  コマンド置換と for ループを組み合わせて
#  キャラクターデータファイルを処理します
# -----------------------------------------------

# -----------------------------------------------
#  作業ディレクトリとデータファイルを準備します
# -----------------------------------------------

work_dir="./yakuza_data"
mkdir -p "${work_dir}"

# 各キャラクターの情報ファイルを作成します
echo "桐生一馬 神室町 極道" > "${work_dir}/kiryu.txt"
echo "真島吾朗 蒼天堀 狂犬" > "${work_dir}/majima.txt"
echo "秋山駿   横浜 探偵" > "${work_dir}/akiyama.txt"
echo "冴島大河 北海道 熊殺し" > "${work_dir}/saejima.txt"
echo "錦山彰   神室町 龍" > "${work_dir}/nishikiyama.txt"

echo "=== seq コマンドと組み合わせた繰り返し ==="
echo ""

# seq コマンドで 1〜5 の数値を生成して反復します
# $() コマンド置換で seq の出力をリストとして使います
for i in $(seq 1 5); do
    echo "  ラウンド ${i} 開始"
done

echo ""
echo "=== find の結果を反復してファイルを処理します ==="
echo ""

# find でテキストファイルを検索してコマンド置換で受け取ります
# スペースを含まないファイル名であれば安全に使えます
for filepath in $(find "${work_dir}" -name "*.txt" | sort); do
    filename=$(basename "${filepath}" .txt)
    content=$(cat "${filepath}")
    echo "  [${filename}] ${content}"
done

echo ""
echo "=== グロブ展開でファイルを安全に反復します ==="
echo ""

# グロブ展開はスペースを含むファイル名にも対応できます
# コマンド置換より安全なため、通常はグロブを推奨します
for f in "${work_dir}"/*.txt; do
    # -f でファイルの存在を確認してから処理します
    if [ -f "${f}" ]; then
        echo "  処理中: $(basename ${f})"
    fi
done

# 作業ディレクトリを削除してクリーンアップします
rm -rf "${work_dir}"
echo ""
echo "クリーンアップ完了。"
$ chmod +x yakuza_cmd_sub_for.sh
$ ./yakuza_cmd_sub_for.sh
=== seq コマンドと組み合わせた繰り返し ===

  ラウンド 1 開始
  ラウンド 2 開始
  ラウンド 3 開始
  ラウンド 4 開始
  ラウンド 5 開始

=== find の結果を反復してファイルを処理します ===

  [akiyama] 秋山駿   横浜 探偵
  [kiryu] 桐生一馬 神室町 極道
  [majima] 真島吾朗 蒼天堀 狂犬
  [nishikiyama] 錦山彰   神室町 龍
  [saejima] 冴島大河 北海道 熊殺し

=== グロブ展開でファイルを安全に反復します ===

  処理中: akiyama.txt
  処理中: kiryu.txt
  処理中: majima.txt
  処理中: nishikiyama.txt
  処理中: saejima.txt

クリーンアップ完了。
yakuza_break_continue.sh
#!/bin/bash
# -----------------------------------------------
#  break と continue の使い方を確認します
# -----------------------------------------------

names=("桐生一馬" "真島吾朗" "秋山駿" "冴島大河" "錦山彰")
# 各キャラクターの状態フラグです(1: 出撃可能, 0: 休養中)
status=(1 1 0 1 0)

echo "=== continue: 休養中のキャラクターをスキップします ==="
echo ""

for ((i=0; i<${#names[@]}; i++)); do
    # status が 0(休養中)のときは continue でスキップします
    if [ "${status[$i]}" -eq 0 ]; then
        echo "  ${names[$i]}: 休養中のためスキップします"
        continue
    fi
    echo "  ${names[$i]}: 出撃準備完了"
done

echo ""
echo "=== break: 桐生一馬が見つかったら探索を中断します ==="
echo ""

target="桐生一馬"
found=0

for chara in "${names[@]}"; do
    echo "  探索中: ${chara}"
    # target と一致したら break でループを抜けます
    if [ "${chara}" = "${target}" ]; then
        echo "  → ${target} を発見しました!探索を終了します。"
        found=1
        break
    fi
done

echo ""
if [ "${found}" -eq 1 ]; then
    echo "発見: ${target}"
else
    echo "${target} は見つかりませんでした。"
fi
$ chmod +x yakuza_break_continue.sh
$ ./yakuza_break_continue.sh
=== continue: 休養中のキャラクターをスキップします ===

  桐生一馬: 出撃準備完了
  真島吾朗: 出撃準備完了
  秋山駿: 休養中のためスキップします
  冴島大河: 出撃準備完了
  錦山彰: 休養中のためスキップします

=== break: 桐生一馬が見つかったら探索を中断します ===

  探索中: 桐生一馬
  → 桐生一馬 を発見しました!探索を終了します。

発見: 桐生一馬

概要

『シェルスクリプト』の for 文には for 変数 in リスト 形式と、bash 専用の for ((初期化; 条件; 更新)) 形式の2種類があります。配列の全要素を反復するときは "${配列名[@]}" とダブルクォートで囲んでスペースを含む要素の分割を防ぎます。コマンド置換($())を使うと seqfind の出力を直接リストとして反復できますが、スペースを含むファイル名には対応できません。ファイルを反復する場合はグロブ展開(*.txt など)を使うほうが安全です。break でループを即座に終了し、continue で現在の反復をスキップして次へ進めます。条件分岐と組み合わせる場合は if 文 も合わせて参照してください。

記事の間違いや著作権の侵害等ございましたらお手数ですがまでご連絡頂ければ幸いです。