やりたいこと検索

バッチファイルでループ処理する

 

こんなことを知りたい人へ向けて書いています

  • Windowsバッチファイルでループ処理のすべてを知りたい方
  • 様々なループ処理の方法を知りたい方
  • 「for」コマンドによるループ処理について詳しく知りたい方
  • 「goto」コマンドを使ったループ処理について詳しく知りたい方
  • ループ処理内での変数の扱いに困っている方
  • (コメント)内容は以下の目次を参照して頂くと分かりやすいと思います。

 

目次

その他の関連しそうな記事

 

決まった回数だけループ処理を行う

まずは、ループ処理の基本である決まった回数だけループ処理を行う方法からです。これには2種類の方法があり、

  • 「for」コマンドを使用した方法
  • 「goto」コマンドとラベルを使用した方法

です。共に一長一短がありますので、どちらを使用するかは自分のやりたいことに合わせて柔軟に使い分けましょう。

「for」コマンドを使用した方法

まずは、「for」コマンドを使用して、決まった回数だけループ処理を行う方法からです。これには「for」コマンドに「/l」オプションをつけて以下のように書きます。

「%%[アルファベット一文字]」の[アルファベット一文字]には任意のアルファベットを一文字入れます(例:「%%a」や「%%n」)。

[開始する数]、[増分]、[終了する数]にはぞれぞれ「ループ開始時の数」、「ループが回るごとに足していく数」、「ループが終了するときの数」を数値で指定します。「%%[アルファベット一文字]」にはここで設定した数が入り、[処理内容]に書いた処理を実行しながらループが回ります。

例えば、「%%n」に1から9までの数を代入して、2ずつ増やしていくループを考えましょう。また、「%%n」に入っている数をコマンドプロンプト画面へ出力するように[処理内容]に記述します。このようなバッチファイルは以下のようになります(loop_9times_for.bat)。

4行目で「for」コマンドに「/l」オプションを指定したループ処理の記述をしました。[開始する数]、[増分]、[終了する数]には、それぞれ1、2、9が指定されています。これで、ループ開始時には「%%n」には1が入り、1ループ毎に2ずつ増加していきます。そして、「%%n」が9になると、ループから出てバッチプログラムが終了します。

以下、実行結果です。

「%%n」には、予想通りの値が入っていることが分かります。

「goto」コマンドとラベルを使用した方法

続いて、別のループ処理の方法です。ここでは、「goto」コマンドと「ラベル」を使った方法を紹介します。「goto」コマンドは、「ラベル」で指定した行に飛ばすという機能を持っています。詳しくは、「ラベルと「goto」(行の移動) -コマンド別解説-」を参照して下さい。

この「goto」コマンドを使って、前の行に戻ることにより、ループ処理を実現します。以下のように書きます。

[ラベル名]には任意の文字列を指定して下さい。ループに使う場合のラベル名としては「:loop」などが使われることが多いようです。1行目と3行目のラベル名を一致させることで、プログラムの実行が3行目に達したとき、再び1行目に戻ります。これが繰り返されることでループ処理が実現されるのです。

[処理内容]にはループさせたい処理を記述するのですが、重要な注意点があります。それは、[処理内容]にループを終わるための条件文を必ず書くということです。そうしないと、永遠にループ処理が終わらなくなってしまいます。

では、例として「for」コマンドを使った時と同じように、1から9までの数を2飛ばしで出力するバッチファイル「loop_9times_goto.bat」を作成してみましょう。以下のようになります。

「for」コマンドに比べると、少し長めのプログラムコードになってしまいましたが、やっていることは単純です。まず、4行目で変数「n」を定義して「1」を代入します。

7行目の「:loop」がラベルであり、最終行の「goto」コマンドでこの行に飛ばされてここへ処理が戻ってきます。この行より下がループ処理する内容になります。

10行目はコマンドプロンプト画面への出力画面です。そして、13行目で変数「n」に2を足しています。「set」コマンドは変数に値を代入する他に、計算を行う機能もあります。詳しくは「set(変数の設定・計算・ユーザーからの入力情報の取得) -コマンド別解説-」をご覧下さい。

そして、16行目がループを終了させるかどうかを判定する条件文です。「if」コマンドを使用して、変数「%n%」が9よりも大きくなれば「exit /b」コマンドによってプログラムを終了します。この行が無ければ、永遠にループが回り続けますので注意しましょう。バッチファイルプログラムが暴走した場合は強制的に処理を停止しましょう。「バッチファイルの実行を強制終了する -やりたいことから検索-」をご覧下さい。

以下、「loop_9times_goto.bat」の実行結果です。

期待通りの出力結果を得ることができました。

 

ここでは、一定回数のループ処理を実現する方法として、「for」コマンドを使う場合と、「goto」コマンドとラベルを使う場合を紹介しました。おそらく「for」コマンドの方がスッキリしていて簡単にコードが書けるから良いと思った方が多いのではないでしょうか。確かに私も一定回数のループ処理には通常は「for」コマンドを使用しています。

しかし、時には「goto」とラベルを使った方法の方が適している場合もあります。それは、

  • 基本的には一定回数だが条件によっては途中でループを抜けたい場合
  • 二重ループを実現したい場合
  • 少し複雑な変数をループ内で使用したい場合

などがあります。今は詳しく述べませんが、このように「goto」とラベルを使うことでしか実現できない場合もありますので、どちらの方法も選択肢として持っておく方が良いでしょう。

 

ファイル名についてループ処理を行う

ファイル名についてループ処理を行うには、「for」コマンドが一番便利です。以下のように書きます。

「%%[アルファベット一文字]」の[アルファベット一文字]には任意のアルファベットを一文字入れます。例えば、「%%a」や「%%n」などとします。後に説明しますが、この「%%a」や「%%n」にファイル名が入ってループが回ることになります。

[ファイル名]には、ループさせたいファイルの名前をワイルドカードなどを使って指定します。例えば、拡張子が「.txt」のテキストファイルだけをループさせたい場合は、[ファイル名]は「*.txt」とします。全てのファイルを対象にループを回した場合は、「*.*」や「*」とすればよいでしょう。

単に、「file.txt」などとすれば、「file.txt」ファイルのみのループになりますが、ループするにしても一つのファイルですので一回だけ処理されてループから出ます。このような指定の仕方はあまり意味がないでしょう。

では、このループを使用した例を見てみましょう。以下のようなフォルダがあったとします。

このフォルダには、6つのファイル入っています。3つは拡張子が「.txt」のテキストファイル、残り3つは拡張子が「.dat」のファイルです。

これら全てのファイル名をループで取得してコマンドプロンプト画面に出力するには、以下のようなバッチファイル「file_loop.bat」を作ればよいでしょう。

注目はループ対象とするファイル名を「*.*」としており、全てのファイルを対象にループを回しているところです。そして、「%%a」にはファイル名が入りながらループが回るはずです。6行目の「echo」コマンドでは、「%%a」に入っているファイル名をコマンドプロンプト画面へ出力しています。

では、このバッチファイル「file_loop.bat」をファイルと同じ場所に置いて実行してみましょう。以下のようになります。

全てのファイルとバッチファイル名が出力されました。バッチファイル名も出力されたのはファイルと同じ場所に置いて実行したからですね。

では次に、拡張子が「.dat」のものだけを対象にループしてみましょう。「file_loop.bat」を書き換えて以下のようにします。名前も「file_loop_only_dat.bat」というふうにしました。

4行目の対象ファイルを「*.dat」と変えました。これで、拡張子が「.dat」のものだけがループの対象となります。以下がバッチファイルを実行した結果です。

正しく「.dat」のファイルだけが出力されました。

最後に、「file3」から始まる名前のファイルだけをループさせることを考えます。そのためには、以下のように書き換えればよいでしょう「file_loop_only_file3.bat」。

4行目の対象ファイルを「file3*.*」と変更しました。これでfile3からファイル名が始まるものだけをループ対象とできます。このように、うまくワイルドカードを使って目的のファイルだけを対象にするように工夫して作っていきましょう。以下、実行結果です。

 

フォルダ名についてループ処理を行う

前節では、ファイル名について説明しましたが、フォルダ名についても基本的には同じです。

ファイル名の場合は「for」コマンドにオプションを付けませんでしたが、フォルダ名に関しては「/d」オプションを付けます。以下のように書きます。

ファイル名の場合から「for」コマンドに「/d」オプションが付いただけです。

では、以下のようなフォルダ構成を考えます。

「フォルダ」というフォルダの中に計6つのフォルダが入っています。3つは「Folder?」、あとの3つは「フォルダ?」という名前です。

これら全てのフォルダ名に対してループ処理をする場合、以下のようなバッチファイルプログラム「folder_loop.bat」となります。

4行目がフォルダに対してループを定義している部分であり、「for」コマンドに「/d」オプションを付けています。これでフォルダだけがループの対象になりました。ファイルなどはループの対象外です。in ( )の括弧内には「フォルダ\*」と指定し、「フォルダ」フォルダ内のすべてのファルダについてループ処理を行うようにしています。

6行目はフォルダ名をコマンドプロンプト画面に表示するコマンドです。

以下、バッチファイルの実行結果です。

「フォルダ」内の6つすべてのフォルダ名が表示されており、全てのフォルダに関してループが回ったことが分かります。

 

では、「F」から始まるフォルダ名に対してのみループを回すにはどのようにすればよいでしょうか?これは、ファイル名ループの時と同様にワイルドカードをうまく使いましょう。以下のようになります。

4行目の「in ( )」の括弧内に「F」を付け加えました。これで、「F」から始まるフォルダ名に対してのみループが行われます。

以下、実行結果です。

このように、「F」から始まるフォルダ名を持つ3つのみのループになりました。

おまけでもう一つ例を出しましょう。フォルダ名の語尾が「3」で終わるフォルダのみをループしたい場合、以下のようになります。

4行目の「in ( )」の括弧内が「*3」となっています。これで、フォルダ名の最後が「3」であるフォルダのみがループされます。これはもう実行結果を示す必要はないでしょう。

 

ファイル内容についてループ処理を行う

次はファイル内容についてのループ処理についてです。ここでは、ファイル内容を読み取り、その内容をバッチファイルの中で利用する方法を紹介します。

バッチファイルでファイルの内容を扱うとき、いくつかのコマンドが使えます。例えば、「more」や「type」コマンドはファイルの内容を表示させることができます。これらに関しては「more(ファイルの内容を表示する) -やりたいことから検索-」や「type(ファイル内容を表示する) -やりたいことから検索-」を参照して下さい。

そして、「for」コマンドも「/f」オプションを使うことで、ファイルの内容を一行ずつ読み込むことができます。使用方法は以下のようになります。

[アルファベット一文字]、[ファイル名]、[処理内容]に関しては前節や前々節と同様なので、ここでは説明は割愛します。

これで、[ファイル名]に指定したファイルから、その内容を一行ずつ読み取り、%%[アルファベット一文字]へ代入しながらループ処理が行われます。

例えば、以下のようなファイルの内容を読み取る場合を考えましょう。

【readfile.txt】

果物の名前が英語(1列目)と日本語(2列目)で書かれてあり、その間はスペースで区切られています。このファイル内容を読み取りコマンドプロンプト画面に表示するには、以下のようなバッチファイル「read_file.bat」になります。

4行目が「readfile.txt」ファイルに対してループ処理をする「for /f」コマンドです。%%sには「readfile.txt」ファイルの内容が一行ずつ代入され、6行目の「echo」コマンドでコマンドプロンプト画面へ出力されます。

以下、実行結果です。

「%%s」には「readfile.txt」ファイルの内容が読み込まれていることが分かります。

2行目以下を読み込む

しかし、よく見ると英語の1列目しか表示されていません。2列目の日本語は「%%s」には代入されていないということです。この原因はバッチファイルでは、「スペース」を区切り文字として認識し、「for /f」コマンドの「%%s」には初めの区切り文字までしか代入されないためです。

二列目以降も読み込みたい場合は「tokens」オプションを用います。使い方は以下の通りです。

「for /f」コマンドの後に「”tokens=[読み込みたい列番号]”」を付け加えました。[読み込みたい列番号]には、読み込みたいファイルの列番号を指定します。例えば、「readfile.txt」の1列目と2列目を読み込んで書き出したい場合は以下のようなバッチファイル「read_file_tokens12.bat」となります。

注目すべきは、まず4行目に「”tokens=1,2″」が指定されていることです。これで1,2行目を読み込むことを宣言しています。

そして、6行目の「%%t」です。「%%s」には「Apple」などの1列目の内容が代入されていましたが、「%%t」には「アップル」などの2列目が代入されています。これは、はじめに指定する[アルファベット1文字]に依存します。いま「%%s」を初めに使っていますので、2行目以下は「%%t」、「%%u」、…に入っていますが、初めに使っている[アルファベット1文字]が「%%a」の場合は、2行目以下は「%%b」、「%%c」、…に入るようになります。このように、2列目以下はアルファベット順の次の文字に入ります

以下、実行結果です。

では、次に以下のファイルを考えましょう。

【readfile_5column.txt】

このファイルから1行目から5行目を読み込んで表示するプログラムは以下のように書けます。

この「”tokens=1,2,3,4,5″」オプションのように、1行目から5行目を連続して表示する場合は、「”tokens=1-5″」のようにハイフンを使って書くこともできます(以下のバッチファイル「read_file_tokens15.bat」)。

このバッチファイルを実行すると以下の図のようになります。

では、最後に「readfile_5column.txt」ファイルから1,3,5行目だけを抜き取って表示するバッチファイルの例「read_file_tokens135.bat」を示します。

「tokens」オプションは「”tokens=1,3,5″」としています。注意すべきは「%%s」、「%%t」、「%%u」とアルファベット順に連番したものに1,3,5行目の値が入ることです。「%%s」、「%%u」「%%w」ではないことに注意してください。

以下、実行結果です。

理想通りの出力結果が得られました。

また、1行目と3~5行目を指定したい場合は、「”tokens=1,3-5″」と書くことができます。

区切り文字を指定する

区切り文字について解説します。ここまではスペースが区切り文字となっていると説明しました。スペース以外でタブも区切り文字として扱われます

では、スペースとタブ以外で区切られている場合はどうでしょうか?例えば、以下のファイル「readfile_5column_2.txt」のように、コンマ「,」、コロン「:」、アンド「&」で文字が区切られていたとします。

【readfile_5column_2.txt】

このような場合は、「delims」オプションを使ってコマンドプロンプトに区切り文字を教えてあげます。

「delims=[区切り文字]」の[区切り文字]には、区切り文字として扱いたい文字を指定します。今の場合はコンマ「,」、コロン「:」、アンド「&」ですから、「delims=,:&」となります。

「readfile_5column_2.txt」ファイルの1列目と4列目を抜き出すバッチファイル「read_file_tokens14.bat」は以下のようになります。

4行目の「delims=,:&」に注目です。ここで、ユーザーが区切り文字を指定しています。

ここで注意すべきは、この状態ではデフォルトでは区切り文字扱いだったスペースやタブが区切り文字にはなっていないことです。確認のため以下のファイルを読み込んでみましょう。

【readfile_5column_3.txt】

最後の1行がスペース区切りとなっています。これを「read_file_tokens14.bat」で読み込んでみましょう。実行結果は以下のようになります。

スペースは区切り文字ではないので、最終行の読み込みは1行全体が1列目扱いになっています。

スペースも区切り文字として扱いたい場合は、「delims=,:& 」のように最後のスペースを加えます。※分かりにくいですが「&」の後にスペースが入っています。よって、上記のバッチファイル「read_file_tokens14.bat」は以下のように書き直せます「read_file_tokens14_space.bat」。

以下、実行結果です。最終行の出力に注目して下さい。

 

ループ内で変数を扱うときの注意

ループ内で変数を扱うときには一つ重要な注意点があります。それは、「for」 コマンドによるループ処理を書いたとき、独自に設定した変数は変化しないということです。例えば、以下の一定回数ループするバッチファイル「check_variable_for.bat」を考えてみましょう。

これは、変数「count」をループ毎に1足していく処理をしています。

4行目で変数「count」に1を代入しています。7行目の「for」コマンドで一定回数ループ処理を行い、13行目で変数「count」に1を足しています。そして、10行目で「%%n」と「count」の値をコマンドプロンプト画面へ出力し確認します。

変数「count」の値は1ずつ増えていくことを期待するでしょう。このバッチファイルを実行した結果が以下の図です。

「%%n」の値は正常に増えていますが、「count」の値は変化していません。

これはコマンドの実行のタイミングに理由があり、詳しくは「forループの中で値を変化させる -やりたいことから検索-」で述べています。ここでは、「for」ループの中で値を変化させるには、「setlocal enabledelayedexpansion」を初めに指定する必要があるとだけ覚えておきましょう。おまじないのようなものだと思っていて構いません。

バッチファイル「check_variable_for.bat」に「setlocal enabledelayedexpansion」を初めに指定したものが以下のバッチファイル「check_variable_for_2.bat」です。

4行目に「setlocal enabledelayedexpansion」を指定しています。

そして、もう一つ重要なことは変数は「%」ではなく、「!」で囲むということです。13行目の変数「count」は「%count%」から「!count!」に変更されています。以下、実行結果です。

今度は変数「count」が変化するようになりました。

以上、「for」コマンドを使ってループ処理を行う場合は、

  • 「setlocal enabledelayedexpansion」を指定する
  • 変数は「%」ではなく、「!」で囲む

という2点を守りましょう。

 

一方、「goto」コマンドとラベルを使ってループ処理をするときは、このようなことをする必要がありません。例えば、本記事の「決まった回数だけループ処理を行う」でバッチファイル「loop_9times_goto.bat」を扱いました。以下にもう一度示します。

これは、「setlocal enabledelayedexpansion」も指定していませんし、「!」も使っていません。それでも変数「n」は変化しました。

 

無限ループを行う

無限ループとは、永遠にループを出ず繰り返し処理を続けるループのことです。通常このような処理を作成する必要はありませんが、あらかじめ決められた回数でループを抜けるのではなく、ある条件によってループを抜けたい場合(条件ループ)を作成するときの基盤になります。

次節で条件ループを紹介しますので、その前に無限ループを作成する方法について解説します。ただし、先ほども述べたように無限ループは永遠に周り続けます。バッチファイルの処理が暴走したら、「Ctrl + C」を入力してください。処理が強制的に中止されます。

まず、「for」コマンドを使った無限ループの作成方法です。「決まった回数だけループ処理を行う」で見たように、決まった回数だけループ処理を行う場合は、「for」コマンドに「/l」オプションをつけて、

と書けました。[増分]には「%%[アルファベット一文字]」に足し込んでいく数を指定し、その数が[終了する数]を超えたらループから抜けるというものでした。

これを利用して無限ループを作成します。[増分]に0を指定しておけば、「%%[アルファベット一文字]」の値はいっこうに増えません。そのため、[終了する数]より大きな値に達することもなくループが永遠に終わらないということです。例として以下のようなバッチファイル「loop_no_stop.bat」を作成してみました。

4行目の「for」コマンドに「in (0,0,0)」と指定していることに注目です。「%%n」は0からスタートして0ずつ増加、すなわち増加しないので永遠にループを抜ける条件を満たさず、無限ループとなります。したがって、6行目の「echo」コマンドが永遠に実行され、コマンドプロンプト画面は「無限ループ中…」で埋め尽くされるでしょう。暴走した場合は、「Ctrl + C」キーを押して強制的に中止します。

ここで紹介した「for」コマンド使った無限ループですが、実はまったく使う機会はありません。その理由は次の節で詳しく説明しますが、ループを抜ける方法が存在しないからです。

 

よく使うのは「goto」コマンドとラベルを用いた無限ループです。上記の「for」コマンドによる無限ループを「goto」コマンドとラベルで書き直すと、以下のバッチファイルようになります。

説明の必要はないと思いますが、4行目のラベル「loop」に最終行の「goto」コマンドから飛んでくることで、ループしています。このバッチファイルには、ループを抜けるためのコマンドがないので、無限ループとなります。

この無限ループを抜けるためには「if」コマンドと「goto」コマンドを使います。「for」ループ内では、「if」コマンドは使えないと言いましたが、「goto」コマンドとラベルのループでは、「if」コマンドと「goto」コマンドが正常に機能します。なので、条件ループでは、この「goto」コマンドが使われることになります。詳しくは次節で紹介します。

 

条件付きループ処理を行う

条件付きループ処理とは、ある条件を満たしたときに処理を抜けるループのことです。これによって、毎回一定回数のループではなく、そのときの状況判断でループを繰り返すか抜けるかを決めることができます。

例えば、変数「count」に1を足していき、その数が6以上になったらループを終了するバッチファイル「count6.bat」は以下のようになります。

4行目で変数「count」に1を代入し初期化を行っています。7行目はループ処理のためのラベルで最終行の「goto」コマンドから飛んでくる場所です。

10行目で変数「count」の値をコマンドプロンプト画面に出力し、13行目で変数「count」に1を足しています。

そして、16行目がループを続けるか、やめるかの条件判断文です。「if」コマンドを使用して変数「count」が6以上かを判断し、もし条件を満たしている場合には「goto :eof」コマンドによってバッチファイルを終了します。「goto :eof」はバッチファイルの処理を終了させるコマンドで、詳しくは「ラベルとgoto(行の移動) -コマンド別解説-」を参照してください。

以下、実行結果です。

変数「count」の値は1から+1ずつ増えていき6に達するとループから抜けるため、コマンドプロンプト画面には5までが表示されています。

 

ループを終わる条件を満たしたとき(上記のバッチファイルでは16行目)、バッチファイルの処理を終了するのではなくループ抜けて次の処理へ移りたい場合は「count6.bat」を少し編集して、以下のようにとします「count6_continue.bat」。

変わったのは、16行目のラベル名(:eof → :continue)。そして、21,22行目です。

16行目でループ処理が終わると21行目の「continue」ラベルへ飛ばすようにしました。これで、ループ終了後は21行目以降のコマンドに続くことになります。

 

さて、ここでは「goto」コマンドとラベルを使ってループ処理を行い、条件ループを構築しました。では「for」コマンドを使ったループで条件ループを行うことはできないのでしょうか?例えば、以下のバッチファイルはどうでしょう。

「count6_continue.bat」が「goto」コマンドとラベルを使って、ループ処理をしているのに対して、上記のバッチファイルは「for」コマンドの無限ループを使っています(10行目)。そして、19行目の「if」コマンドである条件を満たしたときに、「goto」コマンドを使ってループを抜けようとしています。

しかし、 これを実行しても思い通りに動作してくれません。私の場合は途中で固まってしまいました。これは、「for」コマンドの中では「goto」コマンドは使えない・正常に動作しないからです。

つまり、条件ループを作成する場合「for」コマンドは使えず、「goto」コマンドとラベル、そして「if」コマンドを使って実現する必要があるということです。

Windowsバッチファイル初心者へ向けた入門書を作成しました


Windowsバッチファイル初心者の方へ向けた入門書(PDF)を作成しました。


・初めてWindowsバッチファイルを勉強してみようと思っている方

・使ったことはあるが一から基礎を学び直したい方


へ向けて丁寧な解説を行っています。


「全くプログラムを知らない方でも、この入門書を読んだ後には、Windowsバッチファイルの中級者レベルになれるように」をコンセプトに執筆したものです。


この本を読めば、バッチファイルを使ったファイルやフォルダの操作に関しては一通りのことができるようになります。そうなればもう十分中級者と呼べるレベルですので、あとは自分のやりたいことを実現しようとする中で徐々に知識を蓄えていくだけですぐに上級者へなれるでしょう。


詳しくみる

関連ページ

コメントを残す