人気ブログランキング |
- 北の空からみなみへ -
exblog staff

<< しつこく cmd.exe の変... 謹賀新年 そして いまさらコマ... >>
cmd.exe 変数挙動の確認中
2018年 01月 04日
実のところ、遥か昔(バブル期)に、MSDOS 3.1 あたりから win 3.1 くらいまではコマンドプロンプトいじりに燃えてたものの、win 95 始まるあたりからは環境オタクな作業も消えた。今回初めてNT系以降の拡張された環境変数の機能を知った。その程度で、かなり喜べたほどの低レベルオタクなので、当初の目的が達成できたことで舞い上がっていた。
(環境変数内の子指定を変数でできるとか、二重callで遅延環境みたいに動くとか新発見気分)

ですが、よく考えたら挙動をきちんと理解できてはいないし、自宅には やや古いmacはあってもPCはないので、この機会に少しまとめておこうと思う。

コマンドラインから直接打ち込んだ場合と、バッチ内で引用しようと思った場合、違うというのもある。




単純な set では難しく、一段の call set が有効な基本のケース。

> set 月名=&rem 月名という変数をクリア
> set/a dmy=1%date:~5,2%*2-202&set dmy&rem 月の[数]から下駄位置を決めをdmy変数に(08月09月を8bit値扱いされないよう百の桁として計算させている)
> set 月名=%%月名:~%dmy%,2%%&set 月名&rem 変数に関数形式で入れる(後ろは内容確認)この書き方はバッチ内記述。バッチ内でなければ%%の二重打ちは不要
(コマンド実行と結果表示 # は %dmy% の値)
> set 月明=%月名:~%dmy%,2%&set 月名
月名=%月名:~#,2%

> set 月名=睦月如月弥生卯月皐月水無文月葉月長月神無霜月師走&echo 月名=%月名%&call echo 月名 call1=%月名%&call call echo 月名 call2=%月名%&call set 月名=%月名%&set 月名
月名=%月名:~#,2%
月名 call1=睦月
月名 call2=睦月
月名=睦月
今は一月なので上記になりました。
以上は一段で充分な例

次はアレンジしようとして。。コマンドライン上で次の挙動
> set 月名=&set dmy=&rem まずは変数をクリア
> set 月名=%月名:~%dmy%,2%&set 月名&rem 変数を式形式の文字にする.そして表示
月名=%月名:~%dmy%,2%
> set/a dmy=%date:~5,2%*2-2&set dmy&rem 下駄位置のオフセット値をdmy変数に.そして表示
#%dmy%=0> set 月名=%月名%&set 月名&rem まずはそのままどうなるか..
月名=%月名:~%dmy%,2%
ここで、次のコマンドで変数確認確認に echo 表示させてみて。。。わぁぉぅ

> echo 月名=%月名%&call echo 月名1=%月名%&call call echo 月名2=%月名%

闇の一端を垣間見たのか、私がおバカなだけなのか。。。

リカーシブ(自己参照)な記述は設計者にとって悩ましいっていうのがよくわかる。なんてしたり顔しても仕方ないので、いつかは、環境変数の展開するルールってのを明晰に識りたいものだと思った。


~ 前略 〜
:TST$test
echo set $$=%%%%%% 5p&set $$=%%%%%%%%%%&set $$
echo set $$=% 1p&set $$=%%&set $$
echo set $$=%% 2p&set $$=%%%%&set $$
echo set $$=%%% 3p&set $$=%%%%%%&set $$
echo call set $$=%% 2p&call set $$=%%%%&set $$
echo call set $$=%%%% 4p&call set $$=%%%%%%%%&set $$
echo call set $$=%%%%%% 6p&call set $$=%%%%%%%%%%%%&set $$
echo call call set $$=%%% 3p&call call set $$=%%%%%%%%%&set $$
echo call call set $$=%%%%%% 6p&call call set $$=%%%%%%%%%%%%&set $$
echo call call set $$=%%%%%%%%% 9p&call call set $$=%%%%%%%%%%%%%%%%%%&set $$
exit/b

以下、echo off 下の出力
exec$sub=TST$test
set $$=%%%%%% 5p
$$=%%%%%
set $$=% 1p
$$=%
set $$=%% 2p
$$=%%
set $$=%%% 3p
$$=%%%
call set $$=%% 2p
$$=%
call set $$=%%%% 4p
$$=%%
call set $$=%%%%%% 6p
$$=%%%
call call set $$=%%% 3p
$$=%
call call set $$=%%%%%% 6p
$$=%
call call set $$=%%%%%%%%% 9p
$$=%%

挙動がわかるような解らないような。。。

次のはまあ、よくわかるかな。。
キャレット自体は環境変数の % 記号をエスケープはしないのだが、展開された後は消失する性質が見えますね。(ちなみにコマンドラインでは動きますが、バッチでは拒否される書き方です)
無理やり1行にしてるのは、1行展開だと、表に出ている(つまり call call で掘り出さない限り出てこない)変数は展開されないことから、別行の影響を受けないからです。

for %c in ("set fName=" "set fName=%dat^e:/=%" "echo %fName%" "call echo.%fName%" "call call echo+%fName%" "set fName" "echo.call set で (コマンドライン上にfname は空=)1番に入れる" "call set fName1=%fName%" "echo.2段の call call setで 2番に入れる" "call call set fName2=%fName%" "echo.そのまま平段で 自分自身にも入れてみる" "set fNmae=%fName%" "set fName" "echo.使用した変数を消去します" "set fName=" "set fName1=" "set fName2=") do %~c

> set fName=

> set fName=%dat^e:/=%

> echo %fName%
%fName%

> call echo.%fName%
%date:/=%

> call call echo+%fName%
20180104

> set fName
fName=%dat^e:/=%

> echo.call set で (コマンドライン上にfname は空=)1番に入れる
call set で (コマンドライン上にfname は空=)1番に入れる

> call set fName1=%fName%

> echo.2段の call call setで 2番に入れる
2段の call call setで 2番に入れる

> call call set fName2=%fName%

> echo.そのまま平段で 自分自身にも入れてみる
そのまま平段で 自分自身にも入れてみる

> set fNmae=%fName%

> set fName
fName=%dat^e:/=%
fName1=%date:/=%
fName2=20180104

> echo.使用した変数を消去します
使用した変数を消去します

> set fName=

> set fName1=

> set fName2=

結果をecho off でみるとこんな感じ
%fName% ←平段echo
%date:/=% ←1段call echo
20180104 ←2段call echo
fName=%dat^e:/=% ←本当の値表示
call set で (コマンドライン上にfname は空=)1番に入れる
2段の call call setで 2番に入れる
そのまま平段で 自分自身にも入れてみる
(↓はsetで表示されたもの)
fName=%dat^e:/=%
fName1=%date:/=%
fName2=20180104
使用した変数を消去します

以下蛇足=屋上屋を重ねるってのは、循環思考を止める手助けになることも。

for %c in ("set fName=%date:/=%") do %~c
(実行コマンド表示結果)
> set fName=20180104

for %c in ("set fName=%%date:/=%%") do %~c
(実行コマンド表示結果)
> set fName=%20180104%


by bucmacoto | 2018-01-04 23:02 | &Tips;&code;
<< しつこく cmd.exe の変... 謹賀新年 そして いまさらコマ... >>
<< しつこく cmd.exe の変... 謹賀新年 そして いまさらコマ... >>