先日投稿した
.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つのオプションがあります。それぞれの意味は後で詳しくやりますので、気楽に見てください。
(オプション無し) ディレクトリ内を対象にとる
/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」を想定します。
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についてです。
for /f "tokens=1,3" %%i in (hogehoge.txt) do echo %%i %%j
この例では、「1番目と3番目のトークンだけを取ってこい!」と言っています。
hogehoge.txtの各行から1,3番目のトークンを取得してechoするので、
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 ~
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では、トークン同士を区切る文字を変更できます。
このとき、元々の指定であるスペースとタブは区切り文字ではなくなります。これを追加するには、
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 ~
このオプションだけは、テキストファイルを通しません。
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文を使う上でほぼ確実に理解する必要が出てくると思われます。
では、こんなところで解説を終わります。
ご不明な点及び意見・指摘・リクエストなどありましたら、是非コメントまでよろしくお願いします。
Comments
>4.for文の解剖~ in (ループ処理の対象) do コマンド ~
の
>・大文字と小文字は別物になります。数字は使用できません。
ですが、数字はXPと7で使用できています。
8とか10で変わったのでしょうか?
さらに、カナとか漢字も使えます。
JAVAのサイレントアンインストールの例です。
実際には、動かないようにECHOで無効化してあります。
set jre=jre6
for /f "usebackq tokens=3" %%0 in (
call "%ProgramFiles%\Java\%jre%\bin\java.exe" -version 2^>^&1 ^| findstr /c:"version") do (for /f "tokens=1-5 delims=._" %%① in (%%0) do echo;msiexec.exe /qn /x {3248F0A8-6813-11D6-A77B-00B0D0%%①%%②%%③%%④%%⑤0}
)
が、英字以外の文字の使用は推奨されていませんし、数字1字の変数は引数と混同しやすいため使用は控えたほうが無難化と思われます。
使用できるという知識を濫用するのは好ましくないと思い「使用できない」と記述しましたが、不適切でした。申し訳ありません。
ご丁寧にありがとうございます。
可能・不可能、推奨・非推奨は、分けるべきとは思いますが、
出来る事を書くとやってしまうのが人の性でもありますので
不適切と言う程では無いと思います。
せっかく、良い記事を書かれていらっしゃるので
畏まらず、楽に連載してください。
とありますが、ここでいうカレントディレクトリは、バッチファイル自身が存在するフォルダではなく、
バッチファイルを実行する場所、が正しいですよね。
C:\Users\hogehoge\Desktop\に作成したバッチファイルを、コマンドラインでC:\Users\から実行すると、カレントディレクトリはC:\Users\になるはずです。
@radinms 様
記事内ではダブルクリック以外で実行することを考慮していませんでした。確かに記載した方がいいですね。ありがとうございます!
いい記事に恐縮ですが、
for %%a in (boo foo woo) do ~といった単純な列挙のパターンが通ることも基本の方で明示しておいてもらうと分かりみが増すと思います。関連して
for %%f in (%*) do ~というファイルのドラッグ&ドロップ用バッチでよく使うイディオムをどこかに入れていただけるとありがたいです。@kumazo 様
ありがとうございます!
すっかり失念していました。言われるまで書き忘れていたことも忘れていましたね…ありがとうございます!
両方とも適切な場所に入れたいと思います!
仕様はそれであってます。
ただ、申し訳無いのですが解決しました。
ステップ3と4の処理を別々にするのとfor文の中ではラベル処理が使えなくサブルーチンで行うという方法で出来ました。
若干穴のあるコードですが、何とか作れました。
大変、ここの記事は参考になり助かりました。有難うございます。
まず、仕様を確認させて下さい。
ほげほげ.zip 中身 202207011201.csv パスワード zxcvzxcv
202207011201.csv の中身
①関東,②東京,③練馬区,,⑤男
aaaa,bbbb,cccccc,,ee
aaaa,bbbb,cccccc,,ee
aaaa,bbbb,cccccc,,ee
リネーム 202207011201.csv ⇒ ②東京③練馬区⑤男.csv
の内容でよろしいでしょうか?
Let's comment your feelings that are more than good