バッチファイル | テキストファイルを 1 行ずつ読み込む (完全版?)

バッチファイル | テキストファイルを 1 行ずつ読み込む (完全版?)

※2017/03/29 行頭コロンが扱えない問題を修正
初心者の自分が言うのもなんですが、「テキストファイルを 1 行ずつ読み込む」方法をググってみると、多くは不完全なものでした。そのため、なかなか思い通りの動作をせず、苦労しました。
忘れないうちにメモしておこうと思います。
正解 (?) だけ書いてもつまらないので、失敗例から書こうと思います。
以下、下のファイルがバッチファイルと同じディレクトリにあることを仮定します。
ファイル名: test.txt

test0
test1 test1

; test3
test4 & cls
test5 > con
test 6

1.スペースで文字列が切れる

さすがに、ここまでひどいサンプルは検索しても出てきませんでした。
失敗例

@echo off

for /f %%X in (test.txt) do (
echo %%X
)

実行結果

test0
test1
test4
test5
test

これを修正するには、 "delims=" で区切り文字列をなくすよう指定します。

2.";" (セミコロン) で始まる行がスキップされる

これに対処してるサンプル少なかった。
";" (セミコロン) 以下をコメント行として省略するという仕様。
失敗例

@echo off

for /f "delims=" %%X in (test.txt) do (
echo %%X
)

実行結果

test0
test1 test1
test4 & cls
test5 > con
test 6

これを修正するには、 "eol=" でコメント文字列をなくすよう指定します。

3.空行 (空白行) がスキップされる

これは なかなか見つけられなかった。あるサイトなんか「 for で空白行を処理するのは不可能」とまで書いてあった。
まあ確かに for だけでは無理ってのは間違ってないんだけど、コマンドを組み合わせれば望みどおりの処理が可能。
失敗例

@echo off

for /f "delims= eol=" %%X in (test.txt) do (
echo %%X
)

実行結果

test0
test1 test1
; test3
test4 & cls
test5 > con
test 6

これを修正するには、 findstr コマンド等で行番号を付加し、"tokens=1* delims=:" で行番号を分離します。

"tokens=1*" を指定することで、文字列中に ":" (コロン) が含まれていても正しく処理されます。

4.空白行を echo で表示できない

これは for の問題ではありませんが一応。
echo を引数なしで実行してしまうと、現在の設定を表示してしまう。
失敗例

@echo off

for /f "tokens=1* delims=: eol=" %%X in ('findstr /n "^" test.txt') do (
echo %%Y
)

( %%X は 行番号、 %%Y はその行の文字列)
実行結果

test0
test1 test1
ECHO は <OFF> です。
; test3
test4 & cls
test5 > con
test 6

これを修正するには、 echo の直後に "." (ピリオド) を打ちます。 (echo と "." (ピリオド) の間にスペースを入れてはならない)

空白行でない場合もちゃんと表示できるので、文字列が空かどうか調べて分岐する必要はない。

5.完成 ※修正前版

これで完成です。

@echo off

for /f "tokens=1* delims=: eol=" %%X in ('findstr /n "^" test.txt') do (
echo.%%Y
)

実行結果

test0
test1 test1

; test3
test4 & cls
test5 > con
test 6

5+.行頭のコロンが消える ※修正後版

上の方法で、文字列中のコロンは正しく扱えることを確認していたのですが、行頭のコロンが表示されないというコメントをいただき、修正しました… (汗
for では、連続する区切り文字列を一つの区切り文字列として認識してしまうそうです。つまり、「9999::aaa」(間にコロン 2 つ) を最初の「:」(コロン 1 つ) で区切って「:aaa」としてほしいところを、「::」(コロン 2 つ) で区切って「aaa」にしてしまうようです。
なので、やり方を大きく変えて、行頭の数字を消してから、確実にあるコロン一文字を削除する、という形にしてみました!

@echo off

for /f "tokens=* delims=0123456789 eol=" %%X in ('findstr /n "^" test.txt') do (
set Y=%%X
setlocal enabledelayedexpansion
echo.!Y:~1!
endlocal
)

また、文字列を for 中で処理するために遅延環境変数を有効にしていますが、set Y=%%X の時点で有効になっていると、テキスト中に「%PATH%」などの文字列があった時に環境変数の中身が展開されてしまうので注意です!

6.おまけ: echo は かっこ で囲うといいかもしれない

echo は最後のスペース等も出力してしまうので、かっこ で囲って出力する範囲をしっかりさせるといいかもしれない。これなら、標準出力を指定するときとかにスペースを入れられる。

(echo.文字列) >> 出力先

7.終わり

これで完璧なはず。
まだ不完全なところがあるようならコメントください。
では今回はこのへんで。
またいつか~。
↓ブログランキング投票 (クリック) お願いします~


「バッチファイル | テキストファイルを 1 行ずつ読み込む (完全版?)」への7件のフィードバック

  1. 対象のファイル(test.txt)の中に「!」 エスクスクラメーション が存在していても 正しい動作になりますか? 教えて下さい。そのような内容が書かれたサイトを見たことが無いので。よろしくお願いします。

  2. test.txt 中、先頭に「:」(半角コロン)が入っている時、
    これも表示したいのですが、表示されませんでした。

    色々トライしているのですが、うまくいかず、
    良いアイデアございますか。

    恐れ入ります。

  3. > itcさん
    確認しました。行頭以外のコロンはテスト済みだったのですが、行頭のみダメとは…。
    これは、for の tokens, delims を使っている限り対処が難しそうですね…。
    for とは別に文字列操作が必要そうです。後で考えてみます。

    > hyesrさん
    すいません、こちらでは「!」が取り除かれる現象は確認できませんでした…。
    前後の文字列などに依存して発生する問題かもしれないので、問題が起こる文字列を教えていただけますでしょうか?

  4. > itcさん
    行頭コロン対応しました。

    WIndows のコマンドって文字列操作が最低限しかできないので大変でした… (汗
    for で行頭にある行番号を消した後で、コロン一文字だけを消すようにしてみました。

  5. 文中の!!が入ったところから:までが削除されちゃいました
    !!を回避する方法模索中です
    念のためご報告まで

コメントは受け付けていません。