Help us understand the problem. What is going on with this article?

.bat(バッチファイル)のforコマンド解説。

More than 1 year has passed since last update.

 先日投稿した
.bat(バッチファイル)のifコマンド解説。
 で予告した通り、forコマンドについても解説を行います。

 forコマンドは、たまにバッチファイル中に出てきては見る人を混乱に陥れることで有名です。
 ifよりは大分難しいコマンドなので、具体例を多めに取り入れようと思います。
 飛ばし読みはしていないという前提で書いてます。可能な限り、最初からお読みください。

目次

1.forコマンドの基本
 1.そもそもfor文とは?
 2.for文の解剖~ (オプション) ~
 3.for文の解剖~ %%アルファベット1文字 ~
 4.for文の解剖~ in ループ処理の対象 do ~
2.forコマンドの構文①~ オプション無し…ディレクトリ内を対象にとる ~
3.forコマンドの構文②~ /d…ディレクトリ名を対象にとる ~
4.forコマンドの構文③~ /r…サブディレクトリまで対象にとる ~
5.forコマンドの構文④~ /l…指定した値で実行する ~
6.forコマンドの構文⑤~ /f…トークンを代入する ~
 1.トークンオプション~ tokens ~
 2.トークンオプション~ delims ~
 3.トークンオプション~ eol,skip ~
 4.トークンオプション~ usebackq ~
7.まとめ

1.forコマンドの基本

1.そもそもfor文とは?

 for文とは、「ループ」を行うコマンドです。C言語などに触れている方は馴染みがあると思いますが、当然書式は異なります。
 下の文章をご覧ください。

標準形
for (オプション) %%アルファベット1文字 in (ループ処理の対象) do コマンド 

 これがfor文の形です。バッチのコマンドの中で最難の1歩後ろくらいの分かりづらさです…。
 さて、順に解説していきましょう。

2.for文の解剖~ (オプション) ~

 for文におけるオプションとは、後述する「処理対象」の種類を示すものです。
 書き方としては、for文に限らず様々なコマンドにある/a/iみたいなやつです。殆どのオプションは、スラッシュ+アルファベット1字ですね。

 さて、for文には4つのオプションがあります。それぞれの意味は後で詳しくやりますので、気楽に見てください。

for文のオプション一覧
(オプション無し) ディレクトリ内を対象にとる
/d ディレクトリ(フォルダ)名を対象にとる
/r ディレクトリ名及びそのサブディレクトリ内(そのフォルダの中のファイル名やフォルダ名)を対象にとる
/l 値を指定して代入する
/f テキストファイル内の文章に対してトークンを取り出して代入する

3.for文の解剖~ %%アルファベット1文字 ~

 for文では、オプションが決定した処理の対象を変数に代入します。
 が、変数の書式がふつうの環境変数とは異なります。

 どう書くのかというと、%%iといった風に「%%」「アルファベット1文字」です。
 大文字と小文字は別物として判断されます。また、この変数はfor文の中でだけ有効です。

4.for文の解剖~ in (ループ処理の対象) do コマンド ~

 定型文です。「ループ処理の対象」に何を書くかはオプションによって変わりますので今は述べません。
 コマンドは、指定された対象に対して実際に行う処理です。後ほど具体例を見ていきましょう。

まとめ・注意点
 ・for文の変数は、%%iのように、アルファベット1文字を用いた特殊な記法となります。
 ・大文字と小文字は別物になります。数字の使用はサポートされていません。
 ・処理の対象は()内に記述します。
 ・inやdoを忘れないようにしましょう。

2.forコマンドの構文①~ オプション無し…ディレクトリ内を対象にとる ~

 オプション無しの時はこのようになります。

オプション無し
for %%アルファベット1文字 in (対象) do コマンド


例
@echo off
for %%i in (*.bat) do (
echo ファイル名:%%i
type %%i|more
)
pause

 オプションがないとき、処理対象に記載された条件に該当するファイルやフォルダをカレントディレクトリから探して変数に代入します。

 ちなみにカレントディレクトリとは、「現在のディレクトリ」。この場合はバッチファイル自身が存在するフォルダのことです。

 分かりやすく言うと、例えばデスクトップにhoge.batとfuga.batがあったとして、hoge.batに上記の例が書かれていたとします。
 ここでhoge.batを実行すると、

実行の流れ
1:オプションがないので、カレントディレクトリ(ここではデスクトップ)の中身を対象にする。
2:%%iに代入するように指示される。
3:*.batと書かれているので、拡張子がbatのファイル全てを検索する。
4:hoge.batが見つかったので、%%iにhoge.batと代入してdo以降のコマンドを実行する。
5:fuga.batが見つかったので、%%iにfuga.batと代入してdo以降のコマンドを実行する。
6:もうデスクトップにはbatはないので、終了。

(ちなみに、コマンドではファイル名を表示、その下にそのファイルの中身を出力してます。そしてプロンプトの1番下の行に到達するたび一時停止します。)

 分かるまでゆっくり読んでください。

 *.bat*ワイルドカードと言い、そこには1文字以上何文字でも入ります。
 ワイルドカードはもう一種類あり、?も使用できます。これは何でも1文字入ります。

 試しに例に挙げたバッチファイルを作ってみてください。いろいろ分かると思います。

3.forコマンドの構文②~ /d…ディレクトリ名を対象にとる ~

 先ほどの場合とほとんど変わりません。ただし、対象が「ディレクトリの中身」から「ディレクトリの中にあるディレクトリ」になります。
 先ほどの例を使うなら、デスクトップにあるフォルダだけが対象となります。

 それだけ。

4.forコマンドの構文③~ /r…サブディレクトリまで対象にとる ~

 先ほどの場合と略
 ただし、対象がディレクトリの中身全部になります。
 先ほどのバッチファイルの例を使うなら、例えば「デスクトップにある[バッチ]というフォルダの中にあるtest.bat」とかも対象になるわけです。

 /rのあとにディレクトリを指定することで、カレントディレクトリ以外を処理の対象にできます。

こんな感じ。
for /r c:\ %%i in (*.txt) do type %%i|more

さらに、処理対象にディレクトリを指定したいときは先述の/dオプションを併用すれば可能です。
 また、処理対象に.半角ピリオド)を入力すると、ディレクトリをだーっと列挙します。これには/dオプションは不要ですが、列挙されるパスが\.で終わるため、見た目を追求するなら対策が必要です。

まとめ・注意点
 ・オプション無し、および/rではディレクトリの中身。/dではディレクトリ名。
 ・?と*はワイルドカード。それぞれ、1文字と複数文字が入ります。
 ・オプション無しのfor文はめったに使わないと思います。

5.forコマンドの構文④~ /l…指定した値で実行する ~

 正直、ここまでに紹介した/d/rはそこまで使用頻度は高くないと思います(あくまで体感ですが。)
 次に紹介する/lは、おそらくfor文として最も使われる形ではないでしょうか。

値のループ
for /l %%i in (開始値、増分、終了値) do コマンド

例
for /l %%i in (1,2,10) do echo %%i

 この構文では、変数に値を代入してコマンドを実行します。

 例をご覧ください。
 この例では、開始値を1増分を2終了値を10としています。
 そのため、変数には初めに1が代入され、次は2だけ増えて3、次いで5、7、9が代入されます。終了値が10なので、次の値である11には到達しません。
 この例を実行すると、1,3,5,7,9が順に表示されるわけですね。

 さて。勘のいい人はお気づきかもしれませんが、実はこの構文はfor文を使用しなくても書くことができます。

ラベルでも書けます。
set i=1
:loop
コマンド
set /a i+=2
if %i% leq 10 goto loop

 一概にどちらが良いとは言い切れません。場合によります。
 例えば、このiの値をさらに計算する場合などは、ラベルを用いたほうがわかりやすいでしょう。


こんな場合は…(余談!)
目標:10個の数字がnum[1],num[2]...num[10]に入っている。
   隣り合った数字(num[1]とnum[2]、num[2]とnum[3]...)が同じかどうかを比較したい。

for文式
for /l %%i in (1,1,9) do (
    set /a tempnum=%%i+1
    call set tempnum=%%num[!tempnum!]%%
    if !num[%%i]! equ !tempnum! コマンド
)

ラベル式
:loop
    set /a loop+=1,loop2=loop+1
    if !num[%loop%]! equ !num[%loop2%]! コマンド
    if %loop2% lss 10 goto loop

 さて、どちらが見やすいでしょうか。(!num[%変数%]!という記法については、詳しくはここでは省略。意味としては、カッコのなかで変数を2重に展開できます。)
 多分、半分以上の方はラベルのほうが読むのも書くのも楽に感じると思います。カッコの中で変数を計算して、さらにそれを変数に代入するのはかなり変な動作が必要になってくるんです。

 まあ、このくだりは余談です。


まとめ・注意点
 ・/lでは、開始値、増分、終了値を取ってループさせる。
 ・必ずしもforを使う必要はない。
 ・↑でも慣れると非常に便利。
 ・多用されるので、少なくとも/lは読めるようにしておきたい。

6.forコマンドの構文⑤~ /f…トークンを代入する ~

 ラスボスです。

トークンを代入
for /f "トークンオプション" %%i in (処理の対象) do コマンド

トークンオプション一覧
tokens= 何番目のトークンを指定するか?
delims= トークンの区切り文字を指定
eol= この文字から始まる行を無視
skip= 先頭から指定された行数、スキップする。
usebackq コマンドの出力を対象にする

 何をする構文なのかは、見ていれば分かります。テキストファイルなどからトークンを取得して代入する構文です。

 例として、以下のようなテキストファイル「hogehoge.txt」を想定します。

hogehoge.txt
1 2 3 4 5
a b c d e
a:i:u:e:o
hhh o:g ee:e

 基本的に、スペース(Tab)で区切られた文字列1つ1つのことをトークンと呼びます。

1.トークンオプション~ tokens ~

 まずは、tokensについてです。

tokens
for /f "tokens=1,3" %%i in (hogehoge.txt) do echo %%i %%j

 この例では、「1番目と3番目のトークンだけを取ってこい!」と言っています。
 hogehoge.txtの各行から1,3番目のトークンを取得してechoするので、

tokensの結果
1 3
a c
a:i:u:e:o     (注:3番目のトークンは無いので、当然表示されない。)
hhh ee:e

 となります。

ポイント
 2つ以上のトークンを指定したとき、2つ目以降のトークンは指定したアルファベットの次の文字が勝手に宣言、使用されます。
 初めにiを指定したら次はj,k,l...とトークンの数だけ続きます。
 zの次の文字は存在しない(するけど可読性が酷い)ので、x,yなどからトークンを指定するのはお勧めしません。
 
 また、例えば2,3,4,6番目のトークンを取りたいときは2-4,6と表記することもできます。
 1番目のトークンだけを取得するときは、tokensを書く必要はありません。

2.トークンオプション~ delims ~

delims
for /f "tokens=1,3 delims=:" %%i in (hogehoge.txt) do echo %%i %%j

実行結果
1 2 3 4 5
a b c d e
a u
hhh o e

 結果を見てなんとなく察していただけるでしょうか?delimsでは、トークン同士を区切る文字を変更できます。
 このとき、元々の指定であるスペースとタブは区切り文字ではなくなります。これを追加するには、

delims
for /f "tokens=1,3 delims=:  " %%i in (hogehoge.txt) do echo %%i %%j

実行結果
1 3
a c
a u
hhh g

 のようにします。

ポイント
 区切り文字をスペースやタブ以外にも使う(空白も区切り文字に含める)場合、delimsはオプションの最後に、スペースはさらにその最後("の手前)に。スペースとタブ両方使う場合は、タブを先に書きましょう。

3.トークンオプション~ eol,skip ~

for /l "tokens=1,3 eol=a" %%i in (hogehoge.txt) do echo %%i %%j

実行結果
1 3
hhh ee:e

for /l "tokens=1,3 skip=2" in (hogehoge.txt) do echo %%i %%j

実行結果
a:i:u:e:o
hhh ee:e

 特に語ることはありません。
 eolで指定した文字から始まる行を無視skipで指定した行数分先頭から無視です。

4.トークンオプション~ usebackq ~

 このオプションだけは、テキストファイルを通しません。

usebackq
for /f "usebackq tokens=1 delims==" %%i in (`set`) do echo %%i

 usebackqを使用すると、コマンドプロンプト上で使用できるMSDOSコマンドの出力を対象とすることができます。
 この例では、デフォルトで設定されている環境変数名を表示します。

 実際に、以下の内容のバッチファイルを作ってみてください。

比較
@echo off
mode con lines=40 cols=25
set
pause >nul
cls
for /f "usebackq tokens=1 delims==" %%i in (`set`) do echo %%i
pause >nul

 setで表示されるものと、それにfor文を適用したものを順に表示しています。
 通常のsetの出力(最初に出てきたもの)に対してfor文を使っていることになります。

7.まとめ

 さて。後半になるにつれだんだんと難易度が上がっていく解説となりました。
 解説というよりもコマンド使用法みたいになってしまいまして申しわけありません。
 が、for文は慣れが全てだと思いますので、このページを見ながら30分くらいfor文を捏ね繰り回すことを強くお勧めします。言葉で説明されてもピンと来ない部分はどうしても存在すると思いますから。

 ここにリンクを張ることはしませんが、私の他の投稿でifコマンドの解説や汎用的に使えるコマンドラインなどを紹介していますので、よろしければご覧ください。
 特に遅延環境変数については、for文を使う上でほぼ確実に理解する必要が出てくると思われます。

 では、こんなところで解説を終わります。
 ご不明な点及び意見・指摘・リクエストなどありましたら、是非コメントまでよろしくお願いします。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした