「シェルスクリプトの基礎 - 繰り返し文」の版間の差分

提供:MochiuWiki : SUSE, EC, PCB
ナビゲーションに移動 検索に移動
(文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…)
 
(同じ利用者による、間の7版が非表示)
4行目: 4行目:
<br><br>
<br><br>


== for文 ==
== for文の基本 ==
変数iに1から5までの数字を指定して、変数に代入された値をechoで表示させるというサンプルコードを以下に記述する。<br>
変数iに1から5までの数字を指定して、変数に代入された値をechoで表示させるというサンプルコードを以下に記述する。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
13行目: 13行目:
     echo $i
     echo $i
  done
  done
  </source>
   
<br>
  # 出力
  # 出力
  1
  1
21行目: 20行目:
  4
  4
  5
  5
</syntaxhighlight>
<br>
以下の例では、ループ処理するテキスト(aaa、bbb、ccc)をfor文で指定している。<br>
<syntaxhighlight lang="sh">
#!/bin/bash
# 例 : aaa bbb cccを順番に処理する
for x in aaa bbb ccc
do
    echo $x
done
# 出力
aaa
bbb
ccc
</syntaxhighlight>
<br>
以下の例では、リスト内の各要素をダブルクォーテーションで囲み、その単位で繰り返し処理している。<br>
<syntaxhighlight lang="sh">
#!/bin/bash
for i in "aaa bbb" "ccc ddd" "eee fff"
do
    echo $i
done
# 出力
aaa bbb
ccc ddd
eee fff
</syntaxhighlight>
<br>
以下の例では、各変数をダブルクォーテーションで囲み、その単位で繰り返し処理している。<br>
もし、ダブルクォーテーションを付けない場合、各変数内の文字列がスペースで区切られて繰り返し処理される。<br>
<syntaxhighlight lang="sh">
#!/bin/bash
x="aaa bbb"
y="ccc ddd"
z="eee fff"
for i in "$x" "$y" "$z"
do
    echo $i
done
# 出力
aaa bbb
ccc ddd
eee fff
</syntaxhighlight>
<br>
for文に渡す処理を<code>{ }</code>を使用してグルーピングする場合、各グループ内の要素の組み合わせで繰り返し処理できる。<br>
<syntaxhighlight lang="sh">
#!/bin/bash
for X in {A,B,C}-{1,2}
do
    echo $X
done
# 出力
A-1
A-2
B-1
B-2
C-1
C-2
</syntaxhighlight>
<br><br>
<br><br>


26行目: 95行目:
リストの指定方法を以下に記載する。<br>
リストの指定方法を以下に記載する。<br>
<br>
<br>
===== コマンドの実行結果の使用 =====
==== コマンドの実行結果の使用 ====
リスト部分には、コマンドの実行結果を値として使用でき、その場合は、コマンドをバッククォート(`)で囲む必要がある。<br>
リスト部分には、コマンドの実行結果を値として使用でき、その場合は、コマンドをバッククォート(`)で囲む必要がある。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
35行目: 104行目:
     echo $file
     echo $file
  done
  done
  </source>
   
<br>
  # 出力
  # 出力
  /var/log/messages
  /var/log/messages
43行目: 111行目:
  /var/log/messages-20170702
  /var/log/messages-20170702
  /var/log/messages-20170710
  /var/log/messages-20170710
</syntaxhighlight>
<br>
<br>
また、<span style="color:#C00000"><u>'''bashの場合'''</u></span>は、$()も使用できる。<br>
また、<span style="color:#C00000"><u>'''bashの場合'''</u></span>は、$()も使用できる。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
52行目: 121行目:
     echo $file
     echo $file
  done
  done
  </source>
  </syntaxhighlight>
<br>
==== <code>seq</code>コマンドの使用 ====
<code>seq</code>コマンドは、指定した開始の数値から終わりの数値までを表示するというコマンドで、繰り返す回数を指定することができる。<br>
例えば、1から5までをリストとして指定する場合は、<code>seq 1 5</code>と指定する。<br>
<br>
<br>
===== seqコマンドの使用 =====
seqコマンドは、指定した開始の数値から終わりの数値までを表示するというコマンドで、繰り返す回数を指定することができる。<br>
例えば、1から5までをリストとして指定する場合は、seq 1 5と指定する。<br>
また、開始が1からの場合は、開始の数値を省略することもできる。<br>
また、開始が1からの場合は、開始の数値を省略することもできる。<br>
seq 1 5
<code>seq 1 5</code><br>
または
または<br>
seq 5
<code>seq 5</code><br>
または
または<br>
seq 1 1 5
<code>seq 1 1 5</code><br>
<br>
<br>
seqコマンドを使用して、1から5までを範囲指定して、ファイルを作成するというスクリプトを記述する。<br>
seqコマンドを使用して、1から5までを範囲指定して、ファイルを作成するというスクリプトを記述する。<br>
file_1からfile_5までのファイルが作成される。<br>
file_1からfile_5までのファイルが作成される。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
74行目: 143行目:
     touch file_$data
     touch file_$data
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
また、wオプションを使用して、ゼロパディングすることもできる。<br>
また、wオプションを使用して、ゼロパディングすることもできる。<br>
80行目: 149行目:
  seq -w 1 10
  seq -w 1 10
<br>
<br>
===== ブレーズ展開 =====
==== ブレーズ展開 ====
<span style="color:#C00000"><u>'''bashの場合'''</u></span>、ブレーズ展開機能を使用してリストを指定することもできる。<br>
<span style="color:#C00000"><u>'''bashの場合'''</u></span>、ブレーズ展開機能を使用してリストを指定することもできる。<br>
ブレーズ展開は、{開始..最後}といった形式で指定することで、簡単に範囲を指定することができる。<br>
ブレーズ展開は、{開始..最後}といった形式で指定することで、簡単に範囲を指定することができる。<br>
<br>
<br>
例えば、{1..5}で1から5を指定する場合、以下のように記述する。<br>
例えば、{1..5}で1から5を指定する場合、以下のように記述する。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
92行目: 161行目:
     echo $i
     echo $i
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
===== 算術式の使用 =====
==== 算術式の使用 ====
<span style="color:#C00000"><u>'''bashの場合'''</u></span>、以下のように、1から5までを指定することもできる。<br>
<span style="color:#C00000"><u>'''bashの場合'''</u></span>、以下のように、1から5までを指定することもできる。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
103行目: 172行目:
     echo $i
     echo $i
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
===== ファイルの読み込み =====
==== ファイルの読み込み ====
事前にリストに読み込ませるファイルを作成しておき、catコマンド等でファイルの中身を読み込むという方法ある。<br>
事前にリストに読み込ませるファイルを作成しておき、catコマンド等でファイルの中身を読み込むという方法ある。<br>
list.txtファイルを事前に作成して、catコマンドでファイルの中身を読み込む。<br>
list.txtファイルを事前に作成して、catコマンドでファイルの中身を読み込む。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
115行目: 184行目:
     echo $i
     echo $i
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
===== コマンドライン引数の使用 =====
==== コマンドライン引数の使用 ====
リスト部分に"@$"を使用すると、シェルスクリプトを実行する際の引数を、リストの値にすることができる。<br>
リスト部分に"@$"を使用すると、シェルスクリプトを実行する際の引数を、リストの値にすることができる。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
126行目: 195行目:
     echo $i
     echo $i
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
===== 配列変数の使用 =====
==== 配列変数の使用 ====
配列を使用してリストを指定することもできる。<br>
配列を使用してリストを指定することもできる。<br>
配列arrayに1から5を設定して、それをリスト部分で呼び出す。<br>
配列arrayに1から5を設定して、それをリスト部分で呼び出す。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
139行目: 208行目:
     echo $i
     echo $i
  done
  done
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


145行目: 214行目:
以下のサンプルコードでは、変数iが6より小さい間だけ、変数iに代入された値をechoで表示した後、<br>
以下のサンプルコードでは、変数iが6より小さい間だけ、変数iに代入された値をechoで表示した後、<br>
exprコマンドを使用して変数iに1を加算する。<br>
exprコマンドを使用して変数iに1を加算する。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
154行目: 223行目:
     i=`expr $i + 1`
     i=`expr $i + 1`
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
  # 出力
  # 出力
160行目: 229行目:
<br>
<br>
bashのみだが、exprコマンドは遅いので(())を使用した算術式の方が処理が速い。<br>
bashのみだが、exprコマンドは遅いので(())を使用した算術式の方が処理が速い。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
169行目: 238行目:
     i=$(( i + 1 ))
     i=$(( i + 1 ))
  done
  done
  </source>
  </syntaxhighlight>
<br><br>
<br><br>


175行目: 244行目:
条件の指定にはtestコマンド(または[]コマンド)を使用する場合が多いが、それ以外も条件として指定することができる。<br>
条件の指定にはtestコマンド(または[]コマンド)を使用する場合が多いが、それ以外も条件として指定することができる。<br>
<br>
<br>
===== ファイルから読み込む =====
==== ファイルから読み込む ====
readコマンドを使用してlist.txtファイルの内容を読み込み、1行ずつ表示させる。<br>
readコマンドを使用してlist.txtファイルの内容を読み込み、1行ずつ表示させる。<br>
以下のシェルスクリプトを実行すると、list.txtファイルの内容を1行ずつ読み込み、その内容が表示される。<br>
以下のシェルスクリプトを実行すると、list.txtファイルの内容を1行ずつ読み込み、その内容が表示される。<br>
183行目: 252行目:
  ghi
  ghi
<br>
<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
190行目: 259行目:
     echo "$line"
     echo "$line"
  done < ./list.txt
  done < ./list.txt
  </source>
   
<br>
  # 出力
  # 出力
  abc
  abc
  def
  def
  ghi
  ghi
</syntaxhighlight>
<br>
<br>
 
==== 無限ループ ====
===== 無限ループ =====
条件にNULLコマンドである:(コロン)を指定すると、無限ループになる。<br>
条件にNULLコマンドである:(コロン)を指定すると、無限ループになる。<br>
NULLコマンド:は、何もせずに終了コード0(真)を返すので、条件が常に真となるため、無限ループになる。<br>
NULLコマンド:は、何もせずに終了コード0(真)を返すので、条件が常に真となるため、無限ループになる。<br>
204行目: 272行目:
無限ループを終了させるには、Ctrlキー + Cキーで強制的に終了させるか、<br>
無限ループを終了させるには、Ctrlキー + Cキーで強制的に終了させるか、<br>
処理部分でif文またはcase文などの条件分岐で、<code>break</code>、<code>return</code>、<code>exit</code>コマンドを実行する。<br>
処理部分でif文またはcase文などの条件分岐で、<code>break</code>、<code>return</code>、<code>exit</code>コマンドを実行する。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  while :
  while :
  do
  do
     # 処理
     # 処理
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
以下の例では、無限ループにcase文(条件分岐)を組み込んでいる。<br>
以下の例では、無限ループにcase文(条件分岐)を組み込んでいる。<br>
218行目: 286行目:
[y]キーまたは[n]キー以外のキーを入力すると、<code>Push y or n key.</code>と表示する。<br>
[y]キーまたは[n]キー以外のキーを入力すると、<code>Push y or n key.</code>と表示する。<br>
その後、[y]キーまたは[n]キーのいずれかを入力するように促すメッセージを表示して、処理を繰り返す。<br>
その後、[y]キーまたは[n]キーのいずれかを入力するように促すメッセージを表示して、処理を繰り返す。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
231行目: 299行目:
     esac
     esac
  done
  done
  </source>
   
<br>
  # 出力
  # 出力
  Repeat? (y/n) :q  ← yキーまたはnキー以外を入力
  Repeat? (y/n) :q  ← yキーまたはnキー以外を入力
240行目: 307行目:
  Repat? (y/n) :n    ← nキーを入力
  Repat? (y/n) :n    ← nキーを入力
  Repeat end.
  Repeat end.
</syntaxhighlight>
<br><br>
<br><br>


245行目: 313行目:
continueコマンドを実行することにより、以降の処理をスキップして、ループの先頭に移動することができる。<br>
continueコマンドを実行することにより、以降の処理をスキップして、ループの先頭に移動することができる。<br>
また、breakコマンドと同様に、引数を指定することにより、ネストされたループ処理を一気にスキップすることも可能である。<br>
また、breakコマンドと同様に、引数を指定することにより、ネストされたループ処理を一気にスキップすることも可能である。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  while 条件式
  while 条件式
  do
  do
252行目: 320行目:
     …
     …
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
以下の例では、continueコマンドに引数を渡して、ネストされたループを一気にスキップしている。<br>
以下の例では、continueコマンドに引数を渡して、ネストされたループを一気にスキップしている。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  #!/bin/bash
  #!/bin/bash
   
   
286行目: 354行目:
     done
     done
  done
  done
  </source>
  </syntaxhighlight>
<br>
<br>
上記の例の実行結果は、以下の通りである。<br>
上記の例の実行結果は、以下の通りである。<br>
306行目: 374行目:
以下の例では、<code>break</code>コマンドに2を指定して実行することにより、2重ループを一気に抜けている。<br>
以下の例では、<code>break</code>コマンドに2を指定して実行することにより、2重ループを一気に抜けている。<br>
同様に、2重ループの先頭(1つ目のwhile文の先頭)に戻る場合は、<code>continue</code>コマンドの引数に2を指定して実行する。<br>
同様に、2重ループの先頭(1つ目のwhile文の先頭)に戻る場合は、<code>continue</code>コマンドの引数に2を指定して実行する。<br>
  <source lang="sh">
  <syntaxhighlight lang="sh">
  while : # 1つ目のループ
  while : # 1つ目のループ
  do
  do
321行目: 389行目:
     done
     done
  done
  done
  </source>
  </syntaxhighlight>
<br><br>
<br><br>
== コマンドのグルーピングと繰り返し処理 ==
==== コマンドのグルーピング ====
シェル上でコマンドを実行する時、以下のように、コマンドを括弧()で囲みグルーピングすると、<br>
リダイレクト等が全てのコマンドに対して動くようになる。<br>
(command1; command2; command3)
# 例
(echo 'AAA'; echo 'BBB'; echo 'CCC') > output.txt
<br>
また、以下のように、複数行に分けて記述することもできる。<br>
この場合、各コマンドの末尾にセミコロン;は必要ない。<br>
(
  echo 'AAA'
  echo 'BBB'
  echo 'CCC'
) > output.txt
<br>
グルーピングしたコマンドの出力をパイプ処理で繋ぐこともできる。<br>
(
  echo 'foo'
  echo 'bar'
  echo 'yahoo'
  echo 'foo'
) | sort | uniq
<br>
グルーピングしたコマンドは子シェルで実行されるため、<br>
子シェル内でカレントディレクトリや環境変数等を変更した場合、コマンド終了時に元に戻る。<br>
これは、一時的にカレントディレクトリを変更して、コマンドを実行する場合に便利である。<br>
pwd
/home
(cd /etc; pwd)
/etc
pwd
/home
<br>
==== ループ内の出力をリダイレクトする ====
for文やwhile文の内部でechoコマンドを実行した結果は、doneの直後にリダイレクトを記述することで、まとめてファイルに出力できる。<br>
<syntaxhighlight lang="sh">
for x in AAA BBB CCC
do
    echo "$x"
    echo "......"
done > output.txt
# 出力(output.txt)
AAA
......
BBB
......
CCC
......
</syntaxhighlight>
<br>
==== ループ内の出力をパイプで接続する ====
ループ内の出力結果は、パイプ処理|で別のコマンドに繋ぐことができる。<br>
<syntaxhighlight lang="sh">
for x in CCC AAA DDD EEE BBB
do
    echo $x
done | sort
# 出力
AAA
BBB
CCC
DDD
EEE
</syntaxhighlight>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:シェルスクリプト]]
[[カテゴリ:シェルスクリプト]]

2024年10月14日 (月) 10:38時点における最新版

概要

繰り返し文は、変数にリストで指定した値を順番に代入し、その度にdoからdoneまでの処理を実行し、
リストの値を全てを代入し処理が完了したら繰り返しは終了となる。


for文の基本

変数iに1から5までの数字を指定して、変数に代入された値をechoで表示させるというサンプルコードを以下に記述する。

 #!/bin/bash
 
 for i in 1 2 3 4 5
 do
    echo $i
 done
 
 # 出力
 1
 2
 3
 4
 5


以下の例では、ループ処理するテキスト(aaa、bbb、ccc)をfor文で指定している。

 #!/bin/bash
 
 # 例 : aaa bbb cccを順番に処理する
 for x in aaa bbb ccc
 do
    echo $x
 done
 
 # 出力
 aaa
 bbb
 ccc


以下の例では、リスト内の各要素をダブルクォーテーションで囲み、その単位で繰り返し処理している。

 #!/bin/bash
 
 for i in "aaa bbb" "ccc ddd" "eee fff"
 do
    echo $i
 done
 
 # 出力
 aaa bbb
 ccc ddd
 eee fff


以下の例では、各変数をダブルクォーテーションで囲み、その単位で繰り返し処理している。
もし、ダブルクォーテーションを付けない場合、各変数内の文字列がスペースで区切られて繰り返し処理される。

 #!/bin/bash
 
 x="aaa bbb"
 y="ccc ddd"
 z="eee fff"
 
 for i in "$x" "$y" "$z"
 do
    echo $i
 done
 
 # 出力
 aaa bbb
 ccc ddd
 eee fff


for文に渡す処理を{ }を使用してグルーピングする場合、各グループ内の要素の組み合わせで繰り返し処理できる。

 #!/bin/bash
 
 for X in {A,B,C}-{1,2}
 do
    echo $X
 done
 
 # 出力
 A-1
 A-2
 B-1
 B-2
 C-1
 C-2



for文におけるリストの指定

リストの指定方法を以下に記載する。

コマンドの実行結果の使用

リスト部分には、コマンドの実行結果を値として使用でき、その場合は、コマンドをバッククォート(`)で囲む必要がある。

 #!/bin/bash
 
 for file in `ls /var/log/messages*`
 do
    echo $file
 done
 
 # 出力
 /var/log/messages
 /var/log/messages-20170618
 /var/log/messages-20170626
 /var/log/messages-20170702
 /var/log/messages-20170710


また、bashの場合は、$()も使用できる。

 #!/bin/bash
 
 for file in $(ls /var/log/messages*)
 do
    echo $file
 done


seqコマンドの使用

seqコマンドは、指定した開始の数値から終わりの数値までを表示するというコマンドで、繰り返す回数を指定することができる。
例えば、1から5までをリストとして指定する場合は、seq 1 5と指定する。

また、開始が1からの場合は、開始の数値を省略することもできる。
seq 1 5
または
seq 5
または
seq 1 1 5

seqコマンドを使用して、1から5までを範囲指定して、ファイルを作成するというスクリプトを記述する。
file_1からfile_5までのファイルが作成される。

 #!/bin/bash
 
 for data in `seq 5`
 do
    touch file_$data
 done


また、wオプションを使用して、ゼロパディングすることもできる。

# 01から10までを出力する
seq -w 1 10


ブレーズ展開

bashの場合、ブレーズ展開機能を使用してリストを指定することもできる。
ブレーズ展開は、{開始..最後}といった形式で指定することで、簡単に範囲を指定することができる。

例えば、{1..5}で1から5を指定する場合、以下のように記述する。

 #!/bin/bash
 
 for i in {1..5}
 do
    echo $i
 done


算術式の使用

bashの場合、以下のように、1から5までを指定することもできる。

 #!/bin/bash
 
 for ((i=1; i<6; i++))
 do
    echo $i
 done


ファイルの読み込み

事前にリストに読み込ませるファイルを作成しておき、catコマンド等でファイルの中身を読み込むという方法ある。
list.txtファイルを事前に作成して、catコマンドでファイルの中身を読み込む。

 #!/bin/bash
 
 for i in `cat list.txt`
 do
    echo $i
 done


コマンドライン引数の使用

リスト部分に"@$"を使用すると、シェルスクリプトを実行する際の引数を、リストの値にすることができる。

 #!/bin/bash
 
 for i in "$@"
 do
    echo $i
 done


配列変数の使用

配列を使用してリストを指定することもできる。
配列arrayに1から5を設定して、それをリスト部分で呼び出す。

 #!/bin/bash
 
 array=(1 2 3 4 5)
 for i in ${array[@]}
 do
    echo $i
 done



while文

以下のサンプルコードでは、変数iが6より小さい間だけ、変数iに代入された値をechoで表示した後、
exprコマンドを使用して変数iに1を加算する。

 #!/bin/bash
 
 i=1
 while [ $i -lt 6 ]
 do
    echo "$i"
    i=`expr $i + 1`
 done


# 出力
1 2 3 4 5


bashのみだが、exprコマンドは遅いので(())を使用した算術式の方が処理が速い。

 #!/bin/bash
 
 i=1
 while ((i < 6))
 do
    echo $i
    i=$(( i + 1 ))
 done



while文における条件の指定

条件の指定にはtestコマンド(または[]コマンド)を使用する場合が多いが、それ以外も条件として指定することができる。

ファイルから読み込む

readコマンドを使用してlist.txtファイルの内容を読み込み、1行ずつ表示させる。
以下のシェルスクリプトを実行すると、list.txtファイルの内容を1行ずつ読み込み、その内容が表示される。

# list.txtファイルの内容
abc
def
ghi


 #!/bin/bash
 
 while read line
 do
    echo "$line"
 done < ./list.txt
 
 # 出力
 abc
 def
 ghi


無限ループ

条件にNULLコマンドである:(コロン)を指定すると、無限ループになる。
NULLコマンド:は、何もせずに終了コード0(真)を返すので、条件が常に真となるため、無限ループになる。

無限ループを終了させるには、Ctrlキー + Cキーで強制的に終了させるか、
処理部分でif文またはcase文などの条件分岐で、breakreturnexitコマンドを実行する。

 while :
 do
    # 処理
 done


以下の例では、無限ループにcase文(条件分岐)を組み込んでいる。

Repeat? (y/n) :を表示した後、[y]キーを入力すると"Repeat!"と表示して処理が繰り返され、
[n]キーを入力すると、Repeat end.と表示して処理を終了させる。

[y]キーまたは[n]キー以外のキーを入力すると、Push y or n key.と表示する。
その後、[y]キーまたは[n]キーのいずれかを入力するように促すメッセージを表示して、処理を繰り返す。

 #!/bin/bash
 
 while :
 do
    read -p "Repat? (y/n) :" key
    case "$key" in
       y) echo "Repeat!";;
       n) echo "Repeat end."
          break ;;
       *) echo "Push y or n key.";;
    esac
 done
 
 # 出力
 Repeat? (y/n) :q   ← yキーまたはnキー以外を入力
 Push y or n key.
 Repat? (y/n) :y    ← yキーを入力
 Repeat!
 Repat? (y/n) :n    ← nキーを入力
 Repeat end.



continueコマンド

continueコマンドを実行することにより、以降の処理をスキップして、ループの先頭に移動することができる。
また、breakコマンドと同様に、引数を指定することにより、ネストされたループ処理を一気にスキップすることも可能である。

 while 条件式
 docontinuedone


以下の例では、continueコマンドに引数を渡して、ネストされたループを一気にスキップしている。

 #!/bin/bash
 
 # 最初のexitコマンド回避用フラグ
 SKIP="ON"
 
 while :
 do
    if [ "$SKIP" != "ON" ]; then
       echo "continue 2 が実行されました."
       exit 0
    fi
 
    # 以降のループでは上の処理をスキップしない
    SKIP=""
 
    while :
       do
       if [ "$CNT" = "ON" ]; then
          echo "continue が実行されました."
          continue 2
       fi
 
       # continue フラグを立てる
       CNT="ON"
       continue
 
       # continue フラグをオフにする
       CNT=""
    done
 done


上記の例の実行結果は、以下の通りである。

最初のメッセージは、変数CNTにフラグを立てた後、continueコマンドを実行するために出力している。
次に、continue 2が実行されて、処理が1つ上のwhile文の先頭に移動する。
変数SKIPは、2段目の繰り返し処理に入る直前でオフにするので、continue 2コマンドを実行した後、メッセージを出力して終了する。

continue が実行されました.
continue 2 が実行されました.



多重ループの制御

breakコマンドおよびcontinueコマンドは、数値を指定することにより、ネストされた多重ループを越えた移動ができる。
つまり、指定した数値の分だけ、上の階層のループを対象に実行される。
引数を省略した場合は、1を指定した場合と同じ動作になる。

break <数値>
continue <数値>


以下の例では、breakコマンドに2を指定して実行することにより、2重ループを一気に抜けている。
同様に、2重ループの先頭(1つ目のwhile文の先頭)に戻る場合は、continueコマンドの引数に2を指定して実行する。

 while : # 1つ目のループ
 do
    ...
    while : # 2つ目のループ
    do
       ...
       # 1つ目のwhile文の先頭に戻る
       continue 2
       ...
       # 1つ目のwhile文から抜ける
       break 2
       ...
    done
 done



コマンドのグルーピングと繰り返し処理

コマンドのグルーピング

シェル上でコマンドを実行する時、以下のように、コマンドを括弧()で囲みグルーピングすると、
リダイレクト等が全てのコマンドに対して動くようになる。

(command1; command2; command3)

# 例
(echo 'AAA'; echo 'BBB'; echo 'CCC') > output.txt


また、以下のように、複数行に分けて記述することもできる。
この場合、各コマンドの末尾にセミコロン;は必要ない。

(
 echo 'AAA'
 echo 'BBB'
 echo 'CCC'
) > output.txt


グルーピングしたコマンドの出力をパイプ処理で繋ぐこともできる。

(
 echo 'foo'
 echo 'bar'
 echo 'yahoo'
 echo 'foo'
) | sort | uniq


グルーピングしたコマンドは子シェルで実行されるため、
子シェル内でカレントディレクトリや環境変数等を変更した場合、コマンド終了時に元に戻る。
これは、一時的にカレントディレクトリを変更して、コマンドを実行する場合に便利である。

pwd
/home
(cd /etc; pwd)
/etc

pwd
/home


ループ内の出力をリダイレクトする

for文やwhile文の内部でechoコマンドを実行した結果は、doneの直後にリダイレクトを記述することで、まとめてファイルに出力できる。

 for x in AAA BBB CCC
 do
    echo "$x"
    echo "......"
 done > output.txt
 
 # 出力(output.txt)
 AAA
 ......
 BBB
 ......
 CCC
 ......


ループ内の出力をパイプで接続する

ループ内の出力結果は、パイプ処理|で別のコマンドに繋ぐことができる。

 for x in CCC AAA DDD EEE BBB
 do
    echo $x
 done | sort
 
 # 出力
 AAA
 BBB
 CCC
 DDD
 EEE