バッチファイルで外部ファイルから1行ずつ取得する


Y子です。
どのご家庭でも毎日行う、外部データの読み込み。
テキストデータを1行ずつ取り込む作業は、朝食前にササっと終わらせたいものです。;p
その例を、今日は書いてみます。

【2021/04/13 21:00 コードの順番を入れ替え、見やすくしました】

概要・用途

テキストファイルから1行ずつ読み込み、処理に使います。
たとえば、「不要なファイルのリストを用意しておき、削除処理に使う」のような用途を想定します。

コード

(1) 成功例

いくつか対策を盛り込んだ例です。

read_extfile.bat
@echo off

rem 引数がない場合は終了する
if "%~1"=="" (
  echo 引数がありません
  pause
  exit /b
)

rem 外部ファイル(引数から取得)
set str_file=%1

for /f "delims= eol=" %%a in (%str_file%) do (
  echo %%a
)

pause

外部ファイルとして、記号がいっぱいのヤバそうなファイルを用意してみました。
これを取り込みます。

test.txt
 !"#$%&'()*+,-./0123456789:
;<=>?@ABCDEFGHIJKLMNOPQRSTU
VWXYZ[\]^_`abcdefghijklmnop
qrstuvwxyz{|}~ !"#$%&'()*+,
-./0123456789:;<=>?@ABCDEFG
HIJKLMNOPQRSTUVWXYZ[\]^_`ab
cdefghijklmnopqrstuvwxyz{|}
~
実行結果
> read_extfile.bat test.txt
 !"#$%&'()*+,-./0123456789:
;<=>?@ABCDEFGHIJKLMNOPQRSTU
VWXYZ[\]^_`abcdefghijklmnop
qrstuvwxyz{|}~ !"#$%&'()*+,
-./0123456789:;<=>?@ABCDEFG
HIJKLMNOPQRSTUVWXYZ[\]^_`ab
cdefghijklmnopqrstuvwxyz{|}
~
続行するには何かキーを押してください . . .

すべての行が出力されました。

なお、この例のバッチファイルは、外部ファイルのパスを引数で取得しています。
なので、バッチファイルに外部ファイルをマウスでドロップしても、同じ動作になります。

(2) 説明

/f」はfor文のオプションで、「トークンを代入する」という意味です。
変数%%aに、テキストファイルから読み込んだ文字列(トークン)を格納するのに必要です。
なおトークンとは、「区切り文字で区切られた文字列」のことだそうです。

トークンの区切り文字(デリミタ)は、デフォルトでは半角スペースタブです。
また、コメント行は、デフォルトでは;で始まる行で、トークンとして無視されます。

上記の例では、これらをデフォルトから変更しています。
"delims="はデリミタの設定ですが、イコール(=)の右辺が空なので、デリミタを定義なしとしています。
また、"eol="はコメント行の設定ですが、これもイコール(=)の右辺が空なので、行をどんな文字で始めても、コメント行になりません。

(3) 失敗例1

デリミタやコメント行の設定をデフォルトのままにすると、以下のような動作になります。

read_extfile_ng1.bat
@echo off

rem 引数がない場合は終了する
if "%~1"=="" (
  echo 引数がありません
  pause
  exit /b
)

rem 外部ファイル(引数から取得)
set str_file=%1

for /f %%a in (%str_file%) do (
  echo %%a
)

pause

for文の"delims= eol="を削除したので、デフォルトの下記設定になりました。
・デリミタは半角スペースタブ
・コメント行は;始まり

これに、同じ外部ファイルを与えてみます。

実行結果
> read_extfile_ng1.bat test.txt
!"#$%&'()*+,-./0123456789:
VWXYZ[\]^_`abcdefghijklmnop
qrstuvwxyz{|}~
-./0123456789:;<=>?@ABCDEFG
HIJKLMNOPQRSTUVWXYZ[\]^_`ab
cdefghijklmnopqrstuvwxyz{|}
~
続行するには何かキーを押してください . . .

成功例から、下記3か所が変わりました。
・1行目の、先頭の半角スペースが消えた
・2行目(;で始まる行)が、丸ごと消えた
・4行目(qrsで始まる行)の、半角スペース以降が消えた

つまり、このように動作したことになります。
半角スペースがデリミタ。
 →先頭のスペースは無視される(1行目)
 →途中のスペースでトークンが分割され、1件目だけ取得される(4行目)
;が先頭に来るとコメント行。
 →コメント行は無視される(2行目)

(4) 失敗例2

デリミタやコメント行の設定を復活させました。
加えて、遅延環境変数を展開したことで、別の問題が生じた例です。

read_extfile_ng2.bat
@echo off

rem 引数がない場合は終了する
if "%~1"=="" (
  echo 引数がありません
  pause
  exit /b
)

rem 遅延環境変数の展開を有効にする
setlocal enabledelayedexpansion

rem 外部ファイル(引数から取得)
set str_file=%1

for /f "delims= eol=" %%a in (%str_file%) do (
  echo %%a
)

pause
実行結果
> read_extfile_ng2.bat test3.txt
ECHO は <OFF> です。
;<=>?@ABCDEFGHIJKLMNOPQRSTU
VWXYZ[\]^_`abcdefghijklmnop
qrstuvwxyz{|}~ "#$%&'()*+,
-./0123456789:;<=>?@ABCDEFG
HIJKLMNOPQRSTUVWXYZ[\]^_`ab
cdefghijklmnopqrstuvwxyz{|}
~
続行するには何かキーを押してください . . .

成功例から、下記2か所が変わりました。
・1行目が、空文字列として出力された
・4行目(qrsで始まる行)の、!が消えた

遅延環境変数の展開を有効にすると、読み込んだトークン中の!が意味を持ち、未定義の変数として解釈されて空文字列になったり、!だけが消えたりします。

注意

参考にしたサイトの一部には、「eolは空にできないので、外部ファイルで使われない文字を入れて回避する」と書かれていましたが、わたしは空に設定できたようです。原因はわかりませんが、Windowsのバージョンなどに依存するのでしょうか。

おわりに

外部ファイルが読み込めるようになりました。
また夢が広がりますね。
環境ごとに外部ファイルだけを変えることで、同じプログラムで複数の現場に対応できたりとか!

では!