今はもうOSに標準でPowerShellが搭載されている時代です。Windows 2000世代からはWSHが標準搭載されバッチファイルから解放されました。Windows 7, Windows Server 2008ではPowerShellが標準搭載されWSHからも解放されました。.net frameworkも使いつつオブジェクト指向のスクリプトが書ける、そんないい時代になりました。めでたしめでたし…とはいかないのがこの業界です。残念ながら最新のOS上でいまだにバッチファイルを書かなければならない仕事、未だに仮想化されたWindowsNTの面倒を見なければいけない仕事などが存在するのが現実です。

バッチファイルでは実際のところ相当生産性が低いのですが、そんな中で異彩を放つコマンド”for”。その名前からはただの繰り返しコマンドに思えるのですが、実は恐ろしい力を秘めています。実際の所バッチファイルでちょっと複雑なことをやろうと思うとforを効果的に使わないといけません。今回は未だにバッチファイルを書かなければいけない不幸な人のためにforコマンドのTips集をお届けします。

forコマンドのヘルプから読み取れる「できること」

forコマンドは色々な事ができるコマンドなのですが、まじまじとヘルプを見たことが無い人も多いと思います。以下はWindows7のforコマンドのヘルプです。

指定されたコマンドをファイルセットの各ファイルに対して実行します。

 

 

FOR%変数IN(セット)DOコマンド[コマンドパラメーター]

 

 

%変数単一文字の置き換え可能なパラメーターを指定します。

 

(セット)ファイルセットを指定します。ワイルドカードを使用できます。

 

コマンド各ファイルごとに実行するコマンドを指定します。

 

コマンドパラメーター

 

指定されたコマンドのパラメーターまたはスイッチを指定します。

 

 

バッチプログラムでFORコマンドを使用するときは、%変数の代わりに、

 

%%変数を使用してください。変数名では大文字と小文字が区別されるため、

 

%iと%Iは異なります。

 

 

コマンド拡張機能を有効にすると、次のFORコマンドの追加形式

 

がサポートされるようになります:

 

 

FOR/D%変数IN(セット)DOコマンド[コマンドパラメーター]

 

 

セットがワイルドカードを含む場合は、ファイル名ではなくディレクトリ名

 

の一致を指定します。

 

 

FOR/R[[ドライブ:]パス]%変数IN(セット)DOコマンド[コマンドパラメーター]

 

 

[ドライブ:]パスから始めて、ツリーの各ディレクトリでFOR文を実行し

 

ます。/Rの後にディレクトリが指定されていない場合は、現在の

 

ディレクトリが使用されます。セットが単一のピリオドである場合は、

 

ディレクトリツリーの列挙だけを行います。

 

 

FOR/L%変数IN(開始,ステップ,終了)DOコマンド[コマンドパラメーター]

 

 

セットは、ステップの量ごとに変化する開始から終了までの数列です。

 

たとえば、(1,1,5)は12345、(5,-1,1)は(54321)という数列に

 

なります。

 

 

FOR/F["オプション"]%変数IN(ファイルセット)DOコマンド

 

[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN("文字列")DOコマンド[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN'コマンド')DOコマンド[コマンドパラメーター]

 

 

またはusebackqオプションの場合:

 

 

FOR/F["オプション"]%変数IN(ファイルセット)DOコマンド

 

[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN'文字列')DOコマンド[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN(`コマンド`)DOコマンド[コマンドパラメーター]

 

 

ファイルセットは、1つ以上のファイル名です。各ファイルが開かれ、

 

読み取られ、処理されてから、ファイルセットの次のファイルに進みます。

 

処理では、ファイルの読み取り、個々のテキスト行への分割と、0個以上の

 

トークンへの解析が行われます。その後、見つかったトークン文字列を変数値に

 

設定してforループの本体が呼び出されます。既定では、/Fは、各ファイルの

 

各行から、空白で区切られた最初のトークンを取得して渡します。空白行は

 

スキップされます。既定の解析動作を変更するには、省略可能な"オプション"

 

パラメーターを指定します。これは、異なる解析オプションを指定する1つ以上の

 

キーワードを含む、引用符で囲まれた文字列です。キーワードは、次のとおりです:

 

 

eol=c-行末のコメント文字を指定します(1文字)。

 

skip=n-ファイルの先頭でスキップする行数を指定します。

 

delims=xxx-区切り文字のセットを指定します。

 

これは、既定の区切り文字であるスペースとタブを

 

置き換えます。

 

tokens=x,y,m-n-各繰り返しに対して、各行からfor本体に渡す

 

トークンを指定します。これにより、追加の変数名が

 

割り当てられます。

 

m-nの形式は範囲で、m番目からn番目の

 

トークンを指定します。

 

tokens=文字列の最後の文字がアスタリスクである場合は、

 

追加の変数が割り当てられ、最後のトークンが解析された

 

後、行に含まれている残りのテキストを受け取ります。

 

usebackq-次の新しい表示形式を指定します。

 

逆引用符で囲まれた文字列がコマンドとして実行され、

 

一重引用符で囲まれた文字列がリテラル文字列コマンドに

 

なり、ファイルセットのファイル名を二重引用符で

 

囲めるようになります。

 

 

例を参考にしてください:

 

 

FOR/F"eol=;tokens=2,3*delims=,"%iin(myfile.txt)do@echo%i%j%k

 

 

この例は、myfile.txtの各行を解析します。セミコロンで始まる行を無視し、

 

各行の2番目と3番目のトークンをfor本体に渡します。

 

トークンは、コンマまたはスペースで区切られています。

 

for本体の文が%iで2番目のトークンを、%jで3番目のトークンを取得し、

 

%kで3番目以降のすべてのトークンを取得していることに

 

注意してください。

 

スペースを含むファイル名に対しては、二重引用符でファイル名を引用する

 

必要があります。

 

この方法で二重引用符を使うためには、usebackqオプションも

 

使わなければなりません。

 

使わなければ、二重引用符はリテラル文字列の定義として

 

解釈され、解析されます。

 

 

%iはfor文で明示的に宣言され、%jと%kはtokens=オプションで暗黙的に

 

宣言されています。

 

tokens=行を使って26個までのトークンを指定できますが、

 

文字'z'または'Z'よりも高い変数を宣言することはできません。FOR変数名は

 

単一の文字で、大文字と小文字を区別し、グローバルなものであり、一度に

 

アクティブにできるのは合計52個までです。

 

 

また、かっこで囲んだファイルセットを一重引用符で囲み、文字列にすることに

 

より、即時の文字列に対するFOR/F解析ロジックを使うこともできます。

 

これは、ファイルからの単一入力行として処理されます。

 

 

最後に、FOR/Fコマンドを使って、コマンド出力を解析することができます。

 

かっこの中のファイルセットを逆引用符で囲みます。この文字列は、コマンド

 

ラインとして子CMD.EXEに渡されます。出力はメモリにキャプチャされ、

 

ファイルのように解析されます。

 

例:

 

 

FOR/F"usebackqdelims=="%iIN(`set`)DO@echo%i

 

 

この例は、現在の環境の環境変数名を列挙します。

 

 

また、FOR変数参照の置換も拡張されました。

 

次のオプション構文を使うことができます:

 

 

%~I-すべての引用句(")を削除して、%Iを展開します。

 

%~fI-%Iを完全修飾パス名に展開します。

 

%~dI-%Iをドライブ文字だけに展開します。

 

%~pI-%Iをパス名だけに展開します。

 

%~nI-%Iをファイル名だけに展開します。

 

%~xI-%Iをファイル拡張子だけに展開します。

 

%~sI-展開されたパスは短い名前だけを含みます。

 

%~aI-%Iをファイルの属性に展開します。

 

%~tI-%Iファイルの日付/時刻に展開します。

 

%~zI-%Iファイルのサイズに展開します。

 

%~$PATH:I-PATH環境変数に指定されているディレクトリを

 

検索し、最初に見つかった完全修飾名に%Iを

 

展開します。

 

環境変数名が定義されていない場合、または検索

 

してもファイルが見つからなかった場合は、この

 

修飾子を指定すると空の文字列に展開されます。

 

 

修飾子を組み合わせて、複合結果を得ることもできます:

 

 

%~dpI-%Iをドライブ文字とパスだけに展開します。

 

%~nxI-%Iをファイル名と拡張子だけに展開します。

 

%~fsI-%Iを完全なパスと短い名前だけに展開します。

 

%~dp$PATH:I-PATH環境変数に指定されているディレクトリを

 

検索して%Iを探し、最初に見つかったファイル

 

のドライブ文字とパスだけに展開します。

 

%~ftzaI-%IをDIRコマンドの出力行のように展開します。

 

 

上の例の%IとPATHは、他の有効な値で置き換えることができます。

 

%~構文は、有効なFOR変数名によって区切られます。%Iのような大

 

文字の変数を使うと読み取りやすく、大文字と小文字を区別しない修飾子

 

との混乱を避けることができます。

 

ヘルプの長さにまず驚かされますが、「指定されたコマンドをファイル セットの各ファイルに対して実行します。」と、ある通り、基本的には複数のファイルに対してコマンドを実行することが出来るコマンドということになっているようです。

FOR/D%変数IN(セット)DOコマンド[コマンドパラメーター]

 

 

セットがワイルドカードを含む場合は、ファイル名ではなくディレクトリ名

 

の一致を指定します。

 

さらに上記のようにディレクトリに対しても処理を行えることがわかります。

FOR/R[[ドライブ:]パス]%変数IN(セット)DOコマンド[コマンドパラメーター]

 

 

[ドライブ:]パスから始めて、ツリーの各ディレクトリでFOR文を実行し

 

ます。/Rの後にディレクトリが指定されていない場合は、現在の

 

ディレクトリが使用されます。セットが単一のピリオドである場合は、

 

ディレクトリツリーの列挙だけを行います。

 

ディレクトリツリーに対して再帰的に処理も行えるようです。

FOR/L%変数IN(開始,ステップ,終了)DOコマンド[コマンドパラメーター]

 

 

セットは、ステップの量ごとに変化する開始から終了までの数列です。

 

たとえば、(1,1,5)は12345、(5,-1,1)は(54321)という数列に

 

なります。

 

もちろん普通のプログラム言語のように数を変化させながら繰り返し処理もできます。

FOR/F["オプション"]%変数IN(ファイルセット)DOコマンド

 

[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN("文字列")DOコマンド[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN'コマンド')DOコマンド[コマンドパラメーター]

 

 

またはusebackqオプションの場合:

 

 

FOR/F["オプション"]%変数IN(ファイルセット)DOコマンド

 

[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN'文字列')DOコマンド[コマンドパラメーター]

 

FOR/F["オプション"]%変数IN(`コマンド`)DOコマンド[コマンドパラメーター]

 

文字列やコマンドの結果に対しても処理ができちゃいます。

ファイルセットは、1つ以上のファイル名です。各ファイルが開かれ、

 

読み取られ、処理されてから、ファイルセットの次のファイルに進みます。

 

処理では、ファイルの読み取り、個々のテキスト行への分割と、0個以上の

 

トークンへの解析が行われます。その後、見つかったトークン文字列を変数値に

 

設定してforループの本体が呼び出されます。既定では、/Fは、各ファイルの

 

各行から、空白で区切られた最初のトークンを取得して渡します。空白行は

 

スキップされます。

 

さらにファイルに対してはその内容を読み取り行ごとに処理したり、さらに”トークンへの解析”までしてくれちゃいます。

既定の解析動作を変更するには、省略可能な"オプション"

 

パラメーターを指定します。これは、異なる解析オプションを指定する1つ以上の

 

キーワードを含む、引用符で囲まれた文字列です。キーワードは、次のとおりです:

 

 

eol=c-行末のコメント文字を指定します(1文字)。

 

skip=n-ファイルの先頭でスキップする行数を指定します。

 

delims=xxx-区切り文字のセットを指定します。

 

これは、既定の区切り文字であるスペースとタブを

 

置き換えます。

 

tokens=x,y,m-n-各繰り返しに対して、各行からfor本体に渡す

 

トークンを指定します。これにより、追加の変数名が

 

割り当てられます。

 

m-nの形式は範囲で、m番目からn番目の

 

トークンを指定します。

 

tokens=文字列の最後の文字がアスタリスクである場合は、

 

追加の変数が割り当てられ、最後のトークンが解析された

 

後、行に含まれている残りのテキストを受け取ります。

 

usebackq-次の新しい表示形式を指定します。

 

逆引用符で囲まれた文字列がコマンドとして実行され、

 

一重引用符で囲まれた文字列がリテラル文字列コマンドに

 

なり、ファイルセットのファイル名を二重引用符で

 

囲めるようになります。

 

コメント文字の指定や、スキップする行数の指定まで出来ますし、区切り文字の指定、本体に渡すトークン指定までできちゃいます。

また、FOR変数参照の置換も拡張されました。

 

次のオプション構文を使うことができます:

 

 

%~I-すべての引用句(")を削除して、%Iを展開します。

 

%~fI-%Iを完全修飾パス名に展開します。

 

%~dI-%Iをドライブ文字だけに展開します。

 

%~pI-%Iをパス名だけに展開します。

 

%~nI-%Iをファイル名だけに展開します。

 

%~xI-%Iをファイル拡張子だけに展開します。

 

%~sI-展開されたパスは短い名前だけを含みます。

 

%~aI-%Iをファイルの属性に展開します。

 

%~tI-%Iファイルの日付/時刻に展開します。

 

%~zI-%Iファイルのサイズに展開します。

 

%~$PATH:I-PATH環境変数に指定されているディレクトリを

 

検索し、最初に見つかった完全修飾名に%Iを

 

展開します。

 

環境変数名が定義されていない場合、または検索

 

してもファイルが見つからなかった場合は、この

 

修飾子を指定すると空の文字列に展開されます。

 

 

修飾子を組み合わせて、複合結果を得ることもできます:

 

 

%~dpI-%Iをドライブ文字とパスだけに展開します。

 

%~nxI-%Iをファイル名と拡張子だけに展開します。

 

%~fsI-%Iを完全なパスと短い名前だけに展開します。

 

%~dp$PATH:I-PATH環境変数に指定されているディレクトリを

 

検索して%Iを探し、最初に見つかったファイル

 

のドライブ文字とパスだけに展開します。

 

%~ftzaI-%IをDIRコマンドの出力行のように展開します。

 

さらにさらに変数の置換機能まであります。

 

…。さすがはforコマンドですね。「それは別のコマンドを用意したほうがいいんじゃないのか?」という機能まで満載されています。コマンドプロンプト、バッチファイルでは他の機能が貧弱なだけにforコマンドを多用することになります。

では、いくつか例を実行してみたいと思います。この手のものは「習うより慣れろ」ですから是非コマンドプロンプトを立ち上げて一緒に操作しながら読んでもらえればと思います。

ループ処理

まずは、テスト用のディレクトリを作成します。

1:mkdirc:\fortest

 

2:cdc:\fortest

 

テスト用のテキストファイルを用意しましょう。適当に10個程度にしましょうか。せっかくですのでこれもforコマンドで作成してみましょう。

以下のように実行すると10個のテキストファイルが生成されます。

1:c:\fortest>for/L%iIN(1,1,10)DOechosample%i>sample%i.txt

 

2:

 

3:c:\fortest>echosample11>sample1.txt

 

4:

 

5:c:\fortest>echosample21>sample2.txt

 

6:

 

7:c:\fortest>echosample31>sample3.txt

 

8:

 

9:c:\fortest>echosample41>sample4.txt

 

10:

 

11:c:\fortest>echosample51>sample5.txt

 

12:

 

13:c:\fortest>echosample61>sample6.txt

 

14:

 

15:c:\fortest>echosample71>sample7.txt

 

16:

 

17:c:\fortest>echosample81>sample8.txt

 

18:

 

19:c:\fortest>echosample91>sample9.txt

 

20:

 

21:c:\fortest>echosample101>sample10.txt

 

/Lオプションを使用するとこのように変数の中に数字を入れつつ、コマンドを繰り返し実行させることができます。この例では変数%iに対して1から1つづつ値をふやしながら10になるまで「echo sample%1 > sample%i.txt」というコマンドを実行させています。これはいわゆるプログラム言語でいうところのfor文と同じような感じなので理解しやすいのではないかと思います。

ファイル名の取得

次はファイル名の取得の例です。以下のように実行できます。

1:c:\fortest>for%iIN.txt)DO@echo%i

 

2:sample1.txt

 

3:sample10.txt

 

4:sample2.txt

 

5:sample3.txt

 

6:sample4.txt

 

7:sample5.txt

 

8:sample6.txt

 

9:sample7.txt

 

10:sample8.txt

 

11:sample9.txt

 

オプションを付けずにforを実行すると、パターンにマッチするファイル名を取得して変数に1つづつ値を入れつつ、コマンドを実行させることができます。このパターンマッチにはディレクトリ(フォルダ)はマッチしません。以下のように確認できます。

1:c:\fortest>for/L%iIN(1,1,10)DOmkdirdir%i

 

2:

 

3:c:\fortest>mkdirdir1

 

4:

 

5:c:\fortest>mkdirdir2

 

6:

 

7:c:\fortest>mkdirdir3

 

8:

 

9:c:\fortest>mkdirdir4

 

10:

 

11:c:\fortest>mkdirdir5

 

12:

 

13:c:\fortest>mkdirdir6

 

14:

 

15:c:\fortest>mkdirdir7

 

16:

 

17:c:\fortest>mkdirdir8

 

18:

 

19:c:\fortest>mkdirdir9

 

20:

 

21:c:\fortest>mkdirdir10

 

22:

 

23:c:\fortest>for%iINDO@echo%i

 

24:sample1.txt

 

25:sample10.txt

 

26:sample2.txt

 

27:sample3.txt

 

28:sample4.txt

 

29:sample5.txt

 

30:sample6.txt

 

31:sample7.txt

 

32:sample8.txt

 

33:sample9.txt

 

34:

 

35:c:\fortest>dir

 

36:ドライブCのボリュームラベルがありません。

 

37:ボリュームシリアル番号はC0AF-1B4Fです

 

38:

 

39:c:\fortestのディレクトリ

 

40:

 

41:2012/03/1521:59

 

42:2012/03/1521:59

 

43:2012/03/1521:59dir1

 

44:2012/03/1521:59dir10

 

45:2012/03/1521:59dir2

 

46:2012/03/1521:59dir3

 

47:2012/03/1521:59dir4

 

48:2012/03/1521:59dir5

 

49:2012/03/1521:59dir6

 

50:2012/03/1521:59dir7

 

51:2012/03/1521:59dir8

 

52:2012/03/1521:59dir9

 

53:2012/03/1521:5510sample1.txt

 

54:2012/03/1521:5511sample10.txt

 

55:2012/03/1521:5510sample2.txt

 

56:2012/03/1521:5510sample3.txt

 

57:2012/03/1521:5510sample4.txt

 

58:2012/03/1521:5510sample5.txt

 

59:2012/03/1521:5510sample6.txt

 

60:2012/03/1521:5510sample7.txt

 

61:2012/03/1521:5510sample8.txt

 

62:2012/03/1521:5510sample9.txt

 

63:10個のファイル101バイト

 

64:12個のディレクトリ142,859,378,688バイトの空き領域

 

ディレクトリ名の取得

/Dオプションをつけて実行すると、ディレクトリのみがパターンにマッチするようになります。

1:c:\fortest>for/D%iINDO@echo%i

 

2:dir1

 

3:dir10

 

4:dir2

 

5:dir3

 

6:dir4

 

7:dir5

 

8:dir6

 

9:dir7

 

10:dir8

 

11:dir9

 

再帰処理

ディレクトリを指定し、そこから下位のディレクトリのそれぞれでforコマンドを実行させることができます。ちょっとディレクトリ、ファイルを準備してみます。

1:c:\fortest>for/L%iIN(1,1,10)DOechosample%i>\dir%i\sample%i.txt

 

2:

 

3:c:\fortest>echosample11>.\dir1\sample1.txt

 

4:

 

5:c:\fortest>echosample21>.\dir2\sample2.txt

 

6:

 

7:c:\fortest>echosample31>.\dir3\sample3.txt

 

8:

 

9:c:\fortest>echosample41>.\dir4\sample4.txt

 

10:

 

11:c:\fortest>echosample51>.\dir5\sample5.txt

 

12:

 

13:c:\fortest>echosample61>.\dir6\sample6.txt

 

14:

 

15:c:\fortest>echosample71>.\dir7\sample7.txt

 

16:

 

17:c:\fortest>echosample81>.\dir8\sample8.txt

 

18:

 

19:c:\fortest>echosample91>.\dir9\sample9.txt

 

20:

 

21:c:\fortest>echosample101>.\dir10\sample10.txt

 

22:

 

23:c:\fortest>dir/s

 

24:ドライブCのボリュームラベルがありません。

 

25:ボリュームシリアル番号はC0AF-1B4Fです

 

26:

 

27:c:\fortestのディレクトリ

 

28:

 

29:2012/03/1521:59

 

30:2012/03/1521:59

 

31:2012/03/1522:05dir1

 

32:2012/03/1522:05dir10

 

33:2012/03/1522:05dir2

 

34:2012/03/1522:05dir3

 

35:2012/03/1522:05dir4

 

36:2012/03/1522:05dir5

 

37:2012/03/1522:05dir6

 

38:2012/03/1522:05dir7

 

39:2012/03/1522:05dir8

 

40:2012/03/1522:05dir9

 

41:2012/03/1521:5510sample1.txt

 

42:2012/03/1521:5511sample10.txt

 

43:2012/03/1521:5510sample2.txt

 

44:2012/03/1521:5510sample3.txt

 

45:2012/03/1521:5510sample4.txt

 

46:2012/03/1521:5510sample5.txt

 

47:2012/03/1521:5510sample6.txt

 

48:2012/03/1521:5510sample7.txt

 

49:2012/03/1521:5510sample8.txt

 

50:2012/03/1521:5510sample9.txt

 

51:10個のファイル101バイト

 

52:

 

53:c:\fortest\dir1のディレクトリ

 

54:

 

55:2012/03/1522:05

 

56:2012/03/1522:05

 

57:2012/03/1522:0510sample1.txt

 

58:1個のファイル10バイト

 

59:

 

60:c:\fortest\dir10のディレクトリ

 

61:

 

62:2012/03/1522:05

 

63:2012/03/1522:05

 

64:2012/03/1522:0511sample10.txt

 

65:1個のファイル11バイト

 

66:

 

67:c:\fortest\dir2のディレクトリ

 

68:

 

69:2012/03/1522:05

 

70:2012/03/1522:05

 

71:2012/03/1522:0510sample2.txt

 

72:1個のファイル10バイト

 

73:

 

74:c:\fortest\dir3のディレクトリ

 

75:

 

76:2012/03/1522:05

 

77:2012/03/1522:05

 

78:2012/03/1522:0510sample3.txt

 

79:1個のファイル10バイト

 

80:

 

81:c:\fortest\dir4のディレクトリ

 

82:

 

83:2012/03/1522:05

 

84:2012/03/1522:05

 

85:2012/03/1522:0510sample4.txt

 

86:1個のファイル10バイト

 

87:

 

88:c:\fortest\dir5のディレクトリ

 

89:

 

90:2012/03/1522:05

 

91:2012/03/1522:05

 

92:2012/03/1522:0510sample5.txt

 

93:1個のファイル10バイト

 

94:

 

95:c:\fortest\dir6のディレクトリ

 

96:

 

97:2012/03/1522:05

 

98:2012/03/1522:05

 

99:2012/03/1522:0510sample6.txt

 

100:1個のファイル10バイト

 

101:

 

102:c:\fortest\dir7のディレクトリ

 

103:

 

104:2012/03/1522:05

 

105:2012/03/1522:05

 

106:2012/03/1522:0510sample7.txt

 

107:1個のファイル10バイト

 

108:

 

109:c:\fortest\dir8のディレクトリ

 

110:

 

111:2012/03/1522:05

 

112:2012/03/1522:05

 

113:2012/03/1522:0510sample8.txt

 

114:1個のファイル10バイト

 

115:

 

116:c:\fortest\dir9のディレクトリ

 

117:

 

118:2012/03/1522:05

 

119:2012/03/1522:05

 

120:2012/03/1522:0510sample9.txt

 

121:1個のファイル10バイト

 

122:

 

123:ファイルの総数:

 

124:20個のファイル202バイト

 

125:32個のディレクトリ142,869,659,648バイトの空き領域

 

これで、カレントディレクトリにはディレクトリが10個、ファイルが10個。サブディレクトリにはそれぞれファイルが1個づつという状態になりました。現在のディレクトリ以下にある.txtという拡張子を持つファイルを全て表示してみます。

1:c:\fortest>for/R%iIN.txt)DO@echo%i

 

2:c:\fortest\sample1.txt

 

3:c:\fortest\sample10.txt

 

4:c:\fortest\sample2.txt

 

5:c:\fortest\sample3.txt

 

6:c:\fortest\sample4.txt

 

7:c:\fortest\sample5.txt

 

8:c:\fortest\sample6.txt

 

9:c:\fortest\sample7.txt

 

10:c:\fortest\sample8.txt

 

11:c:\fortest\sample9.txt

 

12:c:\fortest\dir1\sample1.txt

 

13:c:\fortest\dir10\sample10.txt

 

14:c:\fortest\dir2\sample2.txt

 

15:c:\fortest\dir3\sample3.txt

 

16:c:\fortest\dir4\sample4.txt

 

17:c:\fortest\dir5\sample5.txt

 

18:c:\fortest\dir6\sample6.txt

 

19:c:\fortest\dir7\sample7.txt

 

20:c:\fortest\dir8\sample8.txt

 

21:c:\fortest\dir9\sample9.txt

 

ディレクトリ名だけ表示するには以下のようにします。

1:c:\fortest>for/R%iINDO@echo%i

 

2:c:\fortest\.

 

3:c:\fortest\dir1\.

 

4:c:\fortest\dir10\.

 

5:c:\fortest\dir2\.

 

6:c:\fortest\dir3\.

 

7:c:\fortest\dir4\.

 

8:c:\fortest\dir5\.

 

9:c:\fortest\dir6\.

 

10:c:\fortest\dir7\.

 

11:c:\fortest\dir8\.

 

12:c:\fortest\dir9\.

 

カレントディレクトリ(.)にだけマッチさせるような感じですね。

ファイルの中身へのアクセス

さて、次はいよいよファイルの中身へのアクセスです。これは/Fオプションで実現できます。

まず、テストのためにファイル内に10行書かれているファイルを用意します。これもfor文でやりましょう。

1:c:\fortest>for/L%iIN(1,1,10)DOecho%i行目sample.txt

 

2:

 

3:c:\fortest>echo1行目1>>sample.txt

 

4:

 

5:c:\fortest>echo2行目1>>sample.txt

 

6:

 

7:c:\fortest>echo3行目1>>sample.txt

 

8:

 

9:c:\fortest>echo4行目1>>sample.txt

 

10:

 

11:c:\fortest>echo5行目1>>sample.txt

 

12:

 

13:c:\fortest>echo6行目1>>sample.txt

 

14:

 

15:c:\fortest>echo7行目1>>sample.txt

 

16:

 

17:c:\fortest>echo8行目1>>sample.txt

 

18:

 

19:c:\fortest>echo9行目1>>sample.txt

 

20:

 

21:c:\fortest>echo10行目1>>sample.txt

 

22:

 

23:c:\fortest>typesample.txt

 

24:1行目

 

25:2行目

 

26:3行目

 

27:4行目

 

28:5行目

 

29:6行目

 

30:7行目

 

31:8行目

 

32:9行目

 

33:10行目

 

このファイルの中身を1行づつ読み取ってみます。

1:c:\fortest>for/F%iIN(sample.txt)DO@echo%i

 

2:1行目

 

3:2行目

 

4:3行目

 

5:4行目

 

6:5行目

 

7:6行目

 

8:7行目

 

9:8行目

 

10:9行目

 

11:10行目

 

「type sample.txt」を実行した結果と同じ結果になるわけですが、1行づつ読み取り、それが変数%iに入れられ、それが1行づつechoされているのがわかりますでしょうか。

もうちょっとわかりやすくするために以下のようにしてみましょうか。

1:c:\fortest>for/F%iIN(sample.txt)DO@echo%iを出力しています。

 

2:1行目を出力しています。

 

3:2行目を出力しています。

 

4:3行目を出力しています。

 

5:4行目を出力しています。

 

6:5行目を出力しています。

 

7:6行目を出力しています。

 

8:7行目を出力しています。

 

9:8行目を出力しています。

 

10:9行目を出力しています。

 

11:10行目を出力しています。

 

あまり内容は変わっていませんが、変数の中にファイルの内容が1行づつ入っていく様子がわかるかと思います。

ちなみに/Fオプションを使っているときにはパターンマッチは行えません。つまり内容を読み込んで処理できるのは1ファイルだということです。

1:c:\fortest>for/F%iIN.txt)DO@echo%iを出力しています。

 

2:ファイル.txtが見つかりません。

 

文字列の処理、コマンドの結果

上記の/Fオプションはファイルの中身に対してだけではなくて、文字列に対してやコマンドの結果に対しても同じように処理できます。

1:c:\fortest>for/F%iIN("hogehoge")DO@echo%i

 

2:hogehoge

 

これだとただ単にechoしているのと変わらないのですが(どう嬉しいのかはもうちょっと待ってください)。文字列は変数に入れておくこともできます。

1:c:\fortest>setmojiretsu=hogehoge

 

2:

 

3:c:\fortest>echo%mojiretsu%

 

4:hogehoge

 

5:

 

6:c:\fortest>for/F%iIN("%mojiretsu%")DO@echo%i

 

7:hogehoge

 

コマンドの結果を処理する場合には「’’」を使ってコマンドを囲むことで実現できます。

1:c:\fortest>for/F%iIN'ipconfig')DO@echo%i

 

2:Windows

 

3:Wireless

 

4:接続固有の

 

5:リンクローカル

 

6:IPv4

 

7:サブネット

 

8:デフォルト

 

9:イーサネット

 

10:メディアの状態.

 

11:接続固有の

 

12:Tunnel

 

13:メディアの状態.

 

14:接続固有の

 

15:Tunnel

 

16:メディアの状態.

 

17:接続固有の

 

18:Tunnel

 

19:接続固有の

 

20:IPv6

 

21:リンクローカル

 

22:デフォルト

 

23:Tunnel

 

24:メディアの状態.

 

25:接続固有の

 

26:Tunnel

 

27:メディアの状態.

 

28:接続固有の

 

おや。出力がipconfigの結果そのままではありませんね。これは規定の状態で以下のようになっているからです。(ヘルプより引用)

既定では、/F は、各ファイルの各行から、空白で区切られた最初のトークンを取得して渡します。空白行はスキップされます。 空白行はスキップされた上で、空白で区切っているわけです。もう一度単純な文字列を処理する例を見ましょう。

1:c:\fortest>for/F%iIN("hoge1hoge2")DO@echo%i

 

2:hoge1

 

文字列は空白で区切られているので1つめのトークンの”hoge1”が%iに入れられています。2つめのトークンである”hoge2”は単純に捨てられています。これも受け取りたい場合にはtokensオプションを指定します。

1:c:\fortest>for/F"tokens=*"%iIN("hoge1hoge2")DO@echo%i

 

2:hoge1hoge2

 

 

1:c:\fortest>for/F"tokens=*"%iIN'ipconfig')DO@echo%i

 

2:WindowsIP構成

 

3:WirelessLANadapterwlan:

 

4:接続固有のDNSサフィックス..:

 

5:リンクローカルIPv6アドレス..:fe80::8d7e:8925:9d7e:38a2%18

 

6:IPv4アドレス..:192.168.1.108

 

7:サブネットマスク..:255.255.255.0

 

8:デフォルトゲートウェイ..:192.168.1.1

 

9:イーサネットアダプターlan:

 

10:メディアの状態..:メディアは接続されていません

 

11:接続固有のDNSサフィックス..:test.local

 

12:Tunneladapterisatap.jbs.local:

 

13:メディアの状態..:メディアは接続されていません

 

14:接続固有のDNSサフィックス..:

 

15:Tunneladapter6TO4Adapter:

 

16:メディアの状態..:メディアは接続されていません

 

17:接続固有のDNSサフィックス..:

 

18:Tunneladapterローカルエリア接続*14:

 

19:接続固有のDNSサフィックス..:

 

20:IPv6アドレス..:2001:0:4137:9e76:1cca:16f7:2518:641c

 

21:リンクローカルIPv6アドレス..:fe80::1cca:16f7:2518:641c%15

 

22:デフォルトゲートウェイ..:::

 

23:Tunneladapterisatap.{0A10F0FC-9ABB-42D0-8C73-C71B2976D3B0}:

 

24:メディアの状態..:メディアは接続されていません

 

25:接続固有のDNSサフィックス..:

 

26:TunneladapterReusableMicrosoft6To4Adapter:

 

27:メディアの状態..:メディアは接続されていません

 

28:接続固有のDNSサフィックス..:

 

上記の2つの例では「tokens=*」とオプションを指定することで空白で区切ることをせず、行全部を1つのトークンにするように指定しました。なので、1行全てが%iに入っています。

空白では区切りつつ、2つの別々の変数で受け取る場合には以下の用にします。

1:c:\fortest>for/F"tokens=1,2"%iIN("hoge1hoge2")DO@echo%i%j

 

2:hoge1hoge2

 

「tokens=1,2」と指定することで1番目と2番目のトークンをそれぞれ%i, %jに入力しています。%iは明示的に宣言されているのですが、%jはいきなり登場しています。これはもうこういうものだと思ってしまうしか無いと思います。%iからはじめるなら、%i, %j, %k …と順番になります。

もちろんtokenの選び方は自由です。

1:c:\fortest>for/F"tokens=1,3"%iIN("hoge1hoge2hoge3")DO@echo%i%j

 

2:hoge1hoge3

 

3:

 

上記のように1番目と3番目を取得するようなこともできます。

1:c:\fortest>for/F"tokens=1,3*"%iIN("hoge1hoge2hoge3hoge4hoge5hoge6")DO@echo%i%j-%k

 

2:hoge1hoge3-hoge4hoge5hoge6

 

上記のように*を使うとその後のすべての文字が次の変数(ここでは%k)に入ります。*の前には「,」は必要ありません。(ちょっと文法的に違和感がありますが・・・)

1:c:\fortest>for/F"tokens=1-5"%iIN("hoge1hoge2hoge3hoge4hoge5")DO@echo%i%j%k%l%m

 

2:hoge1hoge2hoge3hoge4hoge5

 

3:

 

4:c:\fortest>for/F"tokens=1,2,3,4,5"%iIN("hoge1hoge2hoge3hoge4hoge5")DO@echo%i%j%k%l%m

 

5:hoge1hoge2hoge3hoge4hoge5

 

上記のように”token=1-5”のように範囲で書くこともできます。この場合”tokens=1,2,3,4,5”と記述したのと全く同じ意味になります。

次に区切り文字です。規定では空白ですが、delimsオプションで指定することができます。

1:c:\fortest>for/F"tokens=1,2,3delims=,"%iIN("hoge1,hoge2,hoge3")DO@echo%i%j%k%l%m

 

2:hoge1hoge2hoge3%l%m

 

これは,(カンマ)で区切った例です。これを使えばCSVファイルを扱えるわけです。

CSVファイルの読み込み

簡単なCSVファイルを準備します。

1:c:\fortest>echo1-1,1-2,1-3,1-4,1-5>sample.txt

 

2:

 

3:c:\fortest>echo2-1,2-2,2-3,2-4,2-5sample.txt

 

4:

 

5:c:\fortest>echo3-1,3-2,3-3,3-4,3-5sample.txt

 

6:

 

7:c:\fortest>typesample.txt

 

8:1-1,1-2,1-3,1-4,1-5

 

9:2-1,2-2,2-3,2-4,2-5

 

10:3-1,3-2,3-3,3-4,3-5

 

このCSVを1行づつ読み込み、カンマで区切り、5つの変数にそれぞれ値を代入し、表示します。

1:c:\fortest>for/F"tokens=1,2,3,4,5delims=,"%iIN(sample.txt)DO@echo%i%j%k%l%m

 

2:1-11-21-31-41-5

 

3:2-12-22-32-42-5

 

4:3-13-23-33-43-5

 

CSVファイルにコメント行があり読み飛ばしたい時にはeolオプションが使えます。

テスト用のCSVファイルを用意します。

1:c:\fortest>echo#コメント行です。sample.txt

 

2:

 

3:c:\fortest>echo4-1,4-2,4-3,4-4,4-5sample.txt

 

4:

 

5:c:\fortest>typesample.txt

 

6:1-1,1-2,1-3,1-4,1-5

 

7:2-1,2-2,2-3,2-4,2-5

 

8:3-1,3-2,3-3,3-4,3-5

 

9:#コメント行です。

 

10:4-1,4-2,4-3,4-4,4-5

 

1:c:\fortest>for/F"tokens=1,2,3,4,5delims=,eol=#"%iIN(sample.txt)DO@echo%i%j%k%l%m

 

2:1-11-21-31-41-5

 

3:2-12-22-32-42-5

 

4:3-13-23-33-43-5

 

5:4-14-24-34-44-5

 

「eol=#」というオプションを追加することでコメント行をスキップすることが出来ました。

ファイル名に空白を含むファイルを扱いたい時

ここまでの知識でかなりの事が出来るのですが、このままだと「ファイル名に空白を含むものの処理」がうまくできなくて困ってしまいます。ちょっとやろうとしてみましょう。

1:c:\fortest>echohoge>"samplefile.txt"

 

2:

 

3:c:\fortest>dir

 

4:ドライブCのボリュームラベルがありません。

 

5:ボリュームシリアル番号はC0AF-1B4Fです

 

6:

 

7:c:\fortestのディレクトリ

 

8:

 

9:2012/03/1600:00

 

10:2012/03/1600:00

 

11:2012/03/1522:05dir1

 

12:2012/03/1522:05dir10

 

13:2012/03/1522:05dir2

 

14:2012/03/1522:05dir3

 

15:2012/03/1522:05dir4

 

16:2012/03/1522:05dir5

 

17:2012/03/1522:05dir6

 

18:2012/03/1522:05dir7

 

19:2012/03/1522:05dir8

 

20:2012/03/1522:05dir9

 

21:2012/03/1600:007samplefile.txt

 

22:2012/03/1523:51107sample.txt

 

23:2012/03/1521:5510sample1.txt

 

24:2012/03/1521:5511sample10.txt

 

25:2012/03/1521:5510sample2.txt

 

26:2012/03/1521:5510sample3.txt

 

27:2012/03/1521:5510sample4.txt

 

28:2012/03/1521:5510sample5.txt

 

29:2012/03/1521:5510sample6.txt

 

30:2012/03/1521:5510sample7.txt

 

31:2012/03/1521:5510sample8.txt

 

32:2012/03/1521:5510sample9.txt

 

33:12個のファイル215バイト

 

34:12個のディレクトリ142,817,693,696バイトの空き領域

 

1:c:\fortest>for/F%iIN(samplefile.txt)DO@echo%i

 

2:ファイルsampleが見つかりません。

 

3:

 

4:c:\fortest>for/F%iIN("samplefile.txt")DO@echo%i

 

5:sample

 

6:

 

7:c:\fortest>for/F%iIN'samplefile.txt')DO@echo%i

 

8:'sample'は、内部コマンドまたは外部コマンド、

 

9:操作可能なプログラムまたはバッチファイルとして認識されていません。

 

うーん。うまくいきません。こういう時のためにusebackqオプションがあります。このオプションを有効にすると”(ダブルクォート), ‘(シングルクォート), `(バッククォート)の扱いが変わります。

1:c:\fortest>for/F"usebackq"%iIN("samplefile.txt")DO@echo%i

 

2:hoge

 

1:c:\fortest>for/F"usebackq"%iIN'ipconfig')DO@echo%i

 

2:ipconfig

 

3:

 

4:c:\fortest>for/F"usebackq"%iIN(`ipconfig`)DO@echo%i

 

5:Windows

 

6:Wireless

 

7:接続固有の

 

8:リンクローカル

 

9:IPv4

 

10:サブネット

 

11:デフォルト

 

12:イーサネット

 

13:メディアの状態.

 

14:接続固有の

 

15:Tunnel

 

16:メディアの状態.

 

17:接続固有の

 

18:Tunnel

 

19:メディアの状態.

 

20:接続固有の

 

21:Tunnel

 

22:接続固有の

 

23:IPv6

 

24:リンクローカル

 

25:デフォルト

 

26:Tunnel

 

27:メディアの状態.

 

28:接続固有の

 

29:Tunnel

 

30:メディアの状態.

 

31:接続固有の

 

このように、usebackqオプションを有効にすると、ダブルクォートは文字列ではなくてファイル名として扱われます。シングルクオートはコマンドではなく文字列になり、バッククォートがコマンドになります。

置換

変数を置換出来る機能も見ておきましょう。置換というか表現の変更といった方が近いかもしれません。

1:c:\fortest>for/F%iIN(""test"")DO@echo%i

 

2:"test"

 

3:

 

4:c:\fortest>for/F%iIN(""test"")DO@echo%~i

 

5:test

 

変数名の前に~をつけると引用句(“)が削除されます。

1:c:\fortest>for%iIN.txt)DO@echo%i

 

2:samplefile.txt

 

3:sample.txt

 

4:sample1.txt

 

5:sample10.txt

 

6:sample2.txt

 

7:sample3.txt

 

8:sample4.txt

 

9:sample5.txt

 

10:sample6.txt

 

11:sample7.txt

 

12:sample8.txt

 

13:sample9.txt

 

14:

 

15:c:\fortest>for%iIN.txt)DO@echo%~fi

 

16:c:\fortest\samplefile.txt

 

17:c:\fortest\sample.txt

 

18:c:\fortest\sample1.txt

 

19:c:\fortest\sample10.txt

 

20:c:\fortest\sample2.txt

 

21:c:\fortest\sample3.txt

 

22:c:\fortest\sample4.txt

 

23:c:\fortest\sample5.txt

 

24:c:\fortest\sample6.txt

 

25:c:\fortest\sample7.txt

 

26:c:\fortest\sample8.txt

 

27:c:\fortest\sample9.txt

 

変数名の前に~fをつけると絶対パスで表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~di

 

2:c:

 

3:c:

 

4:c:

 

5:c:

 

6:c:

 

7:c:

 

8:c:

 

9:c:

 

10:c:

 

11:c:

 

12:c:

 

13:c:

 

変数名の前に~dをつけるとドライブ名のみ表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~pi

 

2:\fortest\

 

3:\fortest\

 

4:\fortest\

 

5:\fortest\

 

6:\fortest\

 

7:\fortest\

 

8:\fortest\

 

9:\fortest\

 

10:\fortest\

 

11:\fortest\

 

12:\fortest\

 

13:\fortest\

 

変数名の前に~pをつけるとパス名のみ表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~ni

 

2:samplefile

 

3:sample

 

4:sample1

 

5:sample10

 

6:sample2

 

7:sample3

 

8:sample4

 

9:sample5

 

10:sample6

 

11:sample7

 

12:sample8

 

13:sample9

 

変数名の前に~nをつけるとファイル名のみ表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~xi

 

2:.txt

 

3:.txt

 

4:.txt

 

5:.txt

 

6:.txt

 

7:.txt

 

8:.txt

 

9:.txt

 

10:.txt

 

11:.txt

 

12:.txt

 

13:.txt

 

変数名の前に~xをつけると拡張子のみ表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~si

 

2:c:\fortest\SAMPLE~1.TXT

 

3:c:\fortest\sample.txt

 

4:c:\fortest\sample1.txt

 

5:c:\fortest\sample10.txt

 

6:c:\fortest\sample2.txt

 

7:c:\fortest\sample3.txt

 

8:c:\fortest\sample4.txt

 

9:c:\fortest\sample5.txt

 

10:c:\fortest\sample6.txt

 

11:c:\fortest\sample7.txt

 

12:c:\fortest\sample8.txt

 

13:c:\fortest\sample9.txt

 

変数名の前に~sをつけると短い名前を表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~ai

 

2:-a------

 

3:-a------

 

4:-a------

 

5:-a------

 

6:-a------

 

7:-a------

 

8:-a------

 

9:-a------

 

10:-a------

 

11:-a------

 

12:-a------

 

13:-a------

 

変数名の前に~aをつけるとファイルの属性を表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~ti

 

2:2012/03/1600:00

 

3:2012/03/1523:51

 

4:2012/03/1521:55

 

5:2012/03/1521:55

 

6:2012/03/1521:55

 

7:2012/03/1521:55

 

8:2012/03/1521:55

 

9:2012/03/1521:55

 

10:2012/03/1521:55

 

11:2012/03/1521:55

 

12:2012/03/1521:55

 

13:2012/03/1521:55

 

変数名の前に~tをつけると日付/時刻を表示します。

1:c:\fortest>for%iIN.txt)DO@echo%~zi

 

2:7

 

3:107

 

4:10

 

5:11

 

6:10

 

7:10

 

8:10

 

9:10

 

10:10

 

11:10

 

12:10

 

13:10

 

変数名の前に~zをつけるとファイルのサイズを表示します。

1:c:\fortest>for%iIN.txt)DOecho%~$PATH:i

 

2:

 

3:c:\fortest>echo

 

4:ECHOはON>です。

 

1:c:\fortest>setPath=%Path%;c:\fortest

 

2:

 

3:c:\fortest>for%iIN.txt)DOecho%~$PATH:i

 

4:

 

5:c:\fortest>echoc:\fortest\samplefile.txt

 

6:c:\fortest\samplefile.txt

 

上記の例はかなりわかりにくいですが、環境変数PATHの中に記述されているディレクトリを探し、そこに検索結果のファイルやディレクトリが合致すれば表示される、そうでなければ空になる、という動きをします。PATHに含まれているファイル、ディレクトリなのかどうかの判定に使えると思います。

バッチファイルに記述する場合の注意

ここまでforを見てきましたが全て「コマンドプロンプト上で実行する際の記述」であることに注意してください。ヘルプにも以下の記載があります。

バッチ プログラムで FOR コマンドを使用するときは、%変数の代わりに、%%変数を使用してください。 「コマンドプロンプトで動いたものをそのままバッチファイルに貼りつけてはいけない」ということです。

具体的には以下の例であれば

1:c:\fortest>for%iIN.txt)DO@echo%i

 

2:samplefile.txt

 

3:sample.txt

 

4:sample1.txt

 

5:sample10.txt

 

6:sample2.txt

 

7:sample3.txt

 

8:sample4.txt

 

9:sample5.txt

 

10:sample6.txt

 

11:sample7.txt

 

12:sample8.txt

 

13:sample9.txt

 

バッチファイルには以下の用に記述する必要があります。

1:for%%iIN.txt)DO@echo%%i

 

注意して下さい。

 

forの可能性

さて、ここまでforコマンドでできることを見てきました。「かなりの事ができる」ということがお分かりいただけたかと思います。「もういやだ」という人も多いかとは思いますが…。でも、バッチファイルを作るしか無いのであれば仕方が無いです……。

随分このエントリも長くなってしまいました。forを駆使した使える実例に関してはまた別のエントリで紹介したいと思います。