ユーニックス総合研究所

  • home
  • archives
  • bash-for

Bashのfor文の書き方: ループ文で繰り返し処理を行う

  • 作成日: 2020-08-21
  • 更新日: 2023-12-24
  • カテゴリ: Bash

Bashのfor文の書き方

Bashではfor文を使うことが出来ます。
for文は初期化、判定、更新を使った普通のfor文と、inを使った配列などを回すのに適したfor文があります。

Bashのfor文は↓のように書きます。

arr=(1 2 3)  

for ((i=0; i<${#arr[@]}; i++)); do  
    echo ${arr[$i]}  
done  

# または  

for el in "${arr[@]}"; do  
    echo $el  
done  

普通のfor文

Bashでよく使われる普通のfor文は↓のフォーマットで書きます。

for ((初期化; 判定; 更新)); do  
    処理  
done  

for文は↓の流れに沿って実行されます。

  1. 初期化
  2. 判定
  3. 処理
  4. 更新
  5. 2 に戻る

たとえばカウント変数i4より下までカウントし、echoするコードは↓のようになります。

for ((i=0; i<4; i++)); do  
    echo $i  
done  
# 0  
# 1  
# 2  
# 3  

↑のコードの場合、まず「初期化」のi=0が実行されます。
その次に「判定」のi<4が実行され、次に「処理」のecho $iが実行されます。
そして「更新」のi++が実行され、再び「判定」のi<4に戻ります。

「処理」部分では複数行のコードを書くことが出来ます。

inを使ったfor文

inを使ったfor文は配列などを順に走査するのに適しています。

for 変数名 in ${配列名[@]}; do  
    処理  
done  

このfor文は配列の先頭から順に要素にアクセスします。
要素は「変数名」に渡されて、それに対してアクセスすることになります。
たとえば値1, 2, 3が格納された配列をこのfor文で回す場合は↓のようになります。

arr=(1 2 3)  

for el in ${arr[@]}; do  
    echo $el  
done  
# 1  
# 2  
# 3  

${arr[@]}に注目してください。ここで配列の全要素に対してアクセスしています。
ここをダブルクオートで囲むかどうかで要素の走査方法が変わるので注意してください。
たとえば文字列を含んだ配列があって、その文字列がスペースを含んでいるとします。
そうすると、for文でダブルクオートで囲まない場合は、そのスペースがチョップされます。

arr=("The cat" "The dog")  

for el in ${arr[@]}; do  
    echo $el  
done  
# The  
# cat  
# The  
# dog  

一方、for文でダブルクオートで囲む、つまり"${arr[@]}"にした場合は、スペースはチョップされません。

arr=("The cat" "The dog")  

for el in "${arr[@]}"; do  
    echo $el  
done  
# The cat  
# The dog  

ここら辺はBashのfor文のはまりやすいところなので覚えておくと良いと思います。
特に意図が無い限りはダブルクオートで囲むようにしたほうが良いでしょう。

for文のbreak文

for文のループから脱出したい場合はbreakを使います。

for ((i=0; i<4; i++)); do  
    break  
done  

echo $i  
# 0  

↑の場合、for文の処理の冒頭でbreakしているので、ループに入った直後にfor文から脱出しています。
よってecho $iの結果は0になります。これは、ループがカウント0の段階で終了したことを表しています。

break文はif文の中でも機能します。

for ((i=0; i<4; i++)); do  
    if [ $i == 2 ]; then  
        break  
    fi  
done  

echo $i  
# 2  

↑の場合、カウント変数が2になったらif文が真になり、breakによってfor文から脱出します。

for文が入れ子になっている場合、breakは最も近い外側のfor文に対してのみ作用します。

for ((i=0; i<4; i++)); do  
    for ((j=0; j<4; j++)); do  
        break  
    done  
done  

echo $i  
# 4  

echo $j  
# 0  

↑のbreak文はカウント変数jを使用しているfor文に対してのみ作用します。
カウント変数iを使用しているfor文に作用するbreakは↓のように書きます。

for ((i=0; i<4; i++)); do  
    break  
    for ((j=0; j<4; j++)); do  
        echo $j  
    done  
done  

echo $i  
# 0  

↑のbreakはカウント変数jを使用しているfor文には作用しません。

for文のcontinue文

for文のループをスキップしたい場合はcontinue文を使います。

for ((i=0; i<4; i++)); do  
    echo $i  
    continue  
    echo "Come on!"  
done  
# 0  
# 1  
# 2  
# 3  

↑の場合、continue文が実行された時点でそれ以降の処理はスキップされます。
つまりecho "Come on!"は実行されません。

continue文もif文の中で使うことが出来ます。

for ((i=0; i<4; i++)); do  
    if [ $i -ge 2 ]; then  
        continue  
    fi  
    echo $i  
done  
# 0  
# 1  

continue文ももっとも近い外側のfor文に対してのみ作用します。

for ((i=0; i<4; i++)); do  
    echo i $i  
    for ((j=0; j<4; j++)); do  
        continue  
        echo j $j  
    done  
done  
# i 0  
# i 1  
# i 2  
# i 3  

↑の場合、echo j $jは実行されません。

Bashのfor文の使用例

Bashのfor文の使用例です。

1~100までの総和を計算する

$(())は算術式展開です。
ちなみにこれはfor文を使わなくても有名な公式を使えば一発で計算可能です。

sum=0  

for ((i=1; i<=100; i++)); do  
    sum=$(( $sum + $i ))  
done  

echo $sum  
# 5050  

空じゃないファイルを羅列する

lsの出力をfor文で回し、ファイルが空じゃなければ表示します。

for fname in `ls`; do  
    if [ -s "$fname" ]; then  
        echo $fname  
    fi  
done  

0~255のホストにpingを1回送る

指定のネットワークの各ホストにpingを1回だけ送ります。

host="192.168.11."  

for ((i=0; i<=255; i++)); do  
    ip="$host$i"  
    ping -c 1 "$ip"  
done  

問題

Q1: 普通のfor文で、初期化の後に呼ばれるのはなにか答えよ。

  1. 更新
  2. 処理
  3. 判定

Q2: inを使ったfor文はどんな時に適しているか答えよ。

  1. 配列を順に走査したいとき
  2. lsの出力を回すとき
  3. カウント変数をカウントしたいとき

Q3: breakの作用として正しいものを答えよ。

  1. もっとも内側のfor文に対して作用する
  2. もっとも外側のfor文に対して作用する
  3. もっとも近い外側のfor文に対して作用する

答え

Q1: 3
Q2: 1, 2
Q3: 3