【続】標準入力からの読み取り

7/21標準入力からの読み取りにおいて、set /p コマンドによる標準入力からの読み取りをパイプから行った場合、タイミングが合わないので数行おきにしか読めないと書いた。これを確かめてみた。
1行出力ごとに1秒待つプログラムを作成した。(プログラムはフリーのCコンパイラBorland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borlandで作成。簡単なプログラムなのでソース掲載は省略)これをwaitcopy.exeとする。前回のzz.batと組み合わせて、

dir | waitcopy | zz

結果は、

" ドライブ C のボリューム ラベルは XP です"
" ボリューム シリアル番号は 74E4-83F1 です"

と2行表示した後、固まったようになり(*注1*)、数十秒後終わる。おかしい。

普通に dir とやってみると、dir の3行目は空行である。あやしい。

set /p X=

に対して空行を入力してみた。

echo %ERRORLEVEL%
1

駄目だ。zz.bat を再掲するが、

@echo off
setlocal
:loop
set /p X=
if not %ERRORLEVEL% == 0 goto :eof
echo "%X%"
goto loop

つまり、空行ではERRORLEVELが1となるため、EOFと見なされてまい、スクリプトが終わっていたわけだ。
空行とEOFを見分ける手段は無いのか?色々考えて、次のように書き直してみた。

@echo off
set X=
setlocal
:loop
set X=
set /p X=
if not defined X goto :eof
echo "%X%"
goto loop

set /p の前に一旦、X を未定義化しておき、set /p の後で定義されたかどうかで判断してみた。
でも、結果は同じ。
今日の結論:
(1) タイミングをゆっくりにすれば、パイプからでも読める(*注2*)
(2)空行入力とEOFを区別する手段は無い

なかなか、「明日使えるトリビア」にはならない。トリビアの種募集中。

注1: fputs時にエラーチェックするのをサボったため。エラーチェックするときっとbroken pipeのエラーになるでしょう。
注2: 途中にはさむCプログラムを、「読んだのが空行だったら空白1文字を書く」ように改造し、空行が発生しないようにして問題ないことを確認した。