MSDOS BAT

最近BATファイルを書くことが増えてきている。それとともにいくつか不満が出たので書いておく。

  • 変数の参照方法

たとえばこんな感じ

set HOGE="HOGE"
for /l %f in (1,1,3) do
(
echo %HOGE% %f
)

環境変数であるHOGEの参照は%HOGE%、for文に使われる局所変数は%fで参照できる。が、たとえば上記のスクリプトをBATファイルに保存して実行する場合、%fは%%fと書かなければならない。よくわからないが、プロンプト上で記述されるものとBATファイルとして呼び出される場合とでは挙動が異なる様である。
それに関連することとして

たとえばプロンプト上で以下を実行する

> set /a a=1
> for /l %f in (1,1,3) do ( set /a a=%f+1 & echo %a%)

出力結果は以下の通り

> (set /a a=1 + 1   & echo 1 )
21

> (set /a a=2 + 1   & echo 1 )
31

> (set /a a=3 + 1   & echo 1 )
41

aには%f+1の値が入ってほしいのに、DOS側は%a%をこのスクリプト実行時の値にまず置換した上で全体を解釈してしまう。これを回避するために存在するのが環境変数の遅延展開という手法である。これについての情報はweb上にもあるほか、プロンプト上でcmd /?と打つといくつか出てくる。
要は、変数の展開を実行中に行うように指定するのである。
これを実現するには下記のとおり

  1. プロンプトを起動する際に/V :ON を引数に与える
  2. HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\DelayedExpansion に0x1を設定
  3. setlocal enabledelayedexpansionを使う

で、昨日詰まっていたのは3番目である。上でも書いてあるとおり、DOSプロンプトはBATファイルを実行するときとプロンプト上での実行とは挙動が違う。つまりプロンプト上で

> setlocal enabledelayedexpansion

としたからといって以降その窓でその設定が有効になるわけではないのだ。よってこれを利用しようとするにはBATファイルに記述してしまうのが手っ取り早い。先ほどのfor文を使った例だと以下のようになる

setlocal enabledelayedexpansion
set /a a=1
for /l %f in (1,1,3) do ( set /a a=%f+1 & echo !a!)
endlocal

!a!は、環境変数aが遅延展開の対象であることを示している。正直なところ何故これがデフォルトでないのか不思議でたまらない。

あと他にも、shellでいう&がない。(というか知らない)
つまり、スクリプト上であるプログラムを別プロセスで走らせたい場合

...
block_hoge.sh &
...

みたいにやればそこでブロックされず、並列に実行できる、のだが。なんかないのかなぁ。

それと、DOS窓は選択モード(カーソルが窓の一部分を選択している状態)だと、その窓で実行していたプロセスが停止するらしい。何というふざけた仕様。これのせいで機能すさまじい時間のロスをした気がする。

他にもなんかあったかなぁ。とにかく何かとストレスがたまる。何かよい方法はないか?
回答 Cygwin使え
いやそうなんだけどね・・・