†DOSとバッチ†
作成開始日 2018.03.04
最終更新日 2018.03.10
@echo off setlocal enabledelayedexpansion ←遅延環境変数展開を有効に set st=ABC set st=!st!X echo !st! ←ABCXと表示される endlocalただし、遅延展開を有効にしなくても、環境変数の書き換えは可能なことがある。実は、上記のサンプルも、遅延展開が無効でも同じように機能する。しかし、ループ処理などが入ると、両者ははっきりと違った振る舞いをする。たとえば、遅延展開が有効になっていないと;
@echo off set st=ABC for /L %%n in (1,1,10) do ( set st=%st%X echo %st% )
ABCX ABCX …… ABCXと、同じ文字列が10回表示されるだけだが、遅延展開を有効にすると;
@echo off setlocal enabledelayedexpansion set st=ABC for /L %%n in (1,1,10) do ( set st=!st!X echo !st! ) endlocal
ABCX ABCXX ABCXXX …… ABCXXXXXXXXXのように累積的に変化する。通常、このアルゴリズムであれば、こちらの動作を期待するだろう。
for %%f in (*.txt) do ( set orig=%%f set newf=%orig:.txt=.doc% ←文字列置換処理 ren "%orig%" "%newf%" )このアルゴリズム自体は至って単純なもので、拡張子が「.txt」ファイルを見つけ、そこから拡張子を「.doc」に変更したファイル名を生成し、「…….txt」→「…….doc」とリネームしている。が、このバッチを実行しても、期待したような結果は得られない。以下、実際にバッチを実行して結果を確認してみる。ただし、リネーム処理は少々厄介なので、単にorigとnewfの中身を表示するだけのスクリプトに書き換えた。
@echo off ←結果を見易くするため for %%f in (*.txt) do ( set orig=%%f set newf=%orig:.txt=.doc% echo "%orig%" "%newf%" ←renをechoに置き換えた )で、これを実行すると、初回は;
"" "" "" "" ……… "" ""つまり、%orig%も%newf%も空白とみなされてしまっている。
D:\work>@echo %orig% ←D:\workはカレントディレクトリ file3.txt ←該当する最後のファイル名 D:\work>@echo %newf% .txt=.docのように、全然空白ではないのである。%newf%の値がおかしいような気もするが、ともかく空白ではない。
"file3.txt" ".txt=.doc" "file3.txt" ".txt=.doc" …… "file3.txt" ".txt=.doc"と、先ほどコマンドラインで確認した値が、まったく変化せずに該当するファイルの数だけ出力される。
"file3.txt" "file3.doc" "file3.txt" "file3.doc" …… "file3.txt" "file3.doc"今度は置換処理の行われたファイル名が出力されるが、ファイル名はすべて同じ(最後のファイル名)である。
まずは、初回実行時を考えみよう。この場合、環境変数orig、newfは未定義状態=ブランクである。したがって、このバッチは以下のように展開されて実行される。
@echo off for %%f in (*.txt) do ( set orig=%%f set newf=.txt=.doc ←%orig%は空白に展開、「:」は機能文字で、ここでは無効 echo "" "" ←%orig%も%newf%も空白に展開 )ポイントは、forループ内のset命令(set orig=…/set newf=…)自体は実行されているのだが、echo出力が空白に固定されてしまっているため、origやnewfの値がどう変化しようと、echo出力には何の関係もなくなってしまっている点。すなわち、このバッチが終了した時点では、やはりorigには最後のファイル名(ここでは「file3.txt」)が入り、newfには「.txt=.doc」という文字列が入っているのである。
したがって、2回目に実行したときには、この値が引き継がれ;
@echo off for %%f in (*.txt) do ( set orig=%%f set newf=file3.txt:.txt=.doc ←この表記では文法的には機能しない echo "file3.txt" ".txt=.doc" )となる。今回はecho出力が「file3.txt」「.txt=.doc」に固定されてしまう。
@echo off for %%f in (*.txt) do ( set orig=%%f set newf=file3.txt:.txt=.doc ←この表記では文法的には機能しない echo "file3.txt" "file3.doc" )もちろん、この処理を遅延環境変数展開を用いて書き直せば、期待通りに機能する。
@echo off setlocal enabledelayedexpansion for %%f in (*.txt) do ( set orig=%%f set newf=!orig:.txt=.doc! echo "!orig!" "!newf!" ) endlocal