スクリプト中の未定義環境変数の謎

昨日スクリプト中での未定義環境変数の振る舞いが良くわからないと書いた。
実際

set _=
if defined _ if not "%_%" == "%_: =%" set _="%_%"</b>

と書いて実行すると、

コマンドの構文が誤っています。
if defined _ if not "" == " =_"

となってしまう。なぜこうなってしまうかをもう少し調べてみた。変数名 _ が1文字なのが影響を与えているかもしれないので、未定義環境変数には、XYZを使った。

コマンド結果
1set XYZ=-
2echo /%XYZ//XYZ/
3echo /%XYZ%///
4echo /%XYZ:a=b%//a=b/
5echo /%" set XYZ="%///
6echo /XYZ%//XYZ/

コマンドプロンプトで直接未定義環境変数echo %XYZ%とすると、%XYZ%とそのまま表示されるが、スクリプト中では空に置換されれるようである(表3行目参照)。
4行目は環境変数中の文字列置き換えの形式だが、形式全体が空に置換されるのでなく、コロンまでが空に置換され、置き換え文字列はそのまま残されてしまう。その後の%は消える。
5行目であるが、これが難問。%""% に囲まれた部分が丸ごと消えてしまう。" から " までが1つの未定義環境変数名とみなされたのではないか。

以上のことから、

if defined _ if not "%_%" == "%_: =%" set _="%_%"

if defined _ if not "" == " =_"

に変数置換されることがわかる。これでは、if文の後半のコマンド部が無いため、エラーになる。

で、今気づいたが、環境変数名は空白を含んでよい。

set A A=123
echo %A A%

で、123 が表示される。数字でもいいみたい。

set 123=popo
echo %123%

で、popo が表示される。