head コマンドが作れるか? (2)

昨日の続き。
for 文の中で行数をカウントできないとすると外でやるしかない。一旦外に出て帰ってくるわけだ。このとき、外でも for 制御変数が有効かどうかを調べてみる。

rem スクリプト1:
for /f "delims=" %%A in (test.txt) do call :sub
goto :eof
:sub
echo %%A
rem スクリプト2:
for /f "delims=" %%A in (test.txt) do (
 goto :sub
:ret
)
goto :eof
:sub
echo %%A
goto :ret

まずスクリプト1だが、「%A」が行数分表示されるだけである。つまり for 制御変数は for 文の外では有効でない。スクリプト2に至っては「) の使い方が誤っています。」という構文エラーとなる。 :ret) の間に rem の行を入れるとエラーは出なくなるが、「%A」が1つ表示されただけで終わってしまう。for 文から goto で飛び出すとその段階で for 文が終結してしまうようだ。
いずれにせよ、だめである。そこで、表示だけ中でやって行数カウントを外でやることを考える。
goto で外へ行くのは駄目なことはわかったので、call で外のサブルーチンを呼ぶことにする。

rem スクリプト3:
setlocal
set N=0
for /f "delims=" %%A in (test.txt) do (
 call :sub
 echo %%A
)
goto :eof
:sub
set /a N=N+1
if %N% geq 20 exit /b

exit /? によると、exit /b は「現在のバッチ スクリプトを終了する」と書いてあるので使ってみた。しかし、20行でなく全行表示されてしまう。サブルーチンの中で使った場合は、バッチスクリプトの終了でなく、サブルーチンの終了になってしまうようだ。ということは、goto :eof と等価である。意味ねー。

goto で飛び出れば for が終了するのでいいのでは? と、次のようにしてみる。

rem スクリプト4:
setlocal
set N=0
for /f "delims=" %%A in (test.txt) do (
 call :sub
 echo %%A
)
:out
goto :eof
:sub
set /a N=N+1
if %N% geq 20 goto out

が、駄目である。さっきと同じく全行が表示される。サブルーチンから飛び出ても for から飛び出たと判断してもらえないようだ。

つづく