BLOGTIMES
2019/09/24

bat を遅延環境変数を使わないように書き換える

  bat 
このエントリーをはてなブックマークに追加

Windows の bat には遅延環境変数というハマりやすい機能があります。

bat では環境変数はその行に入ったときに即時に展開されるという性質があり、IF や FOR などの括弧内は1行と見なされるので、特に FOR ループの中で環境変数を変更しようとしたりすると、うまく変数が更新されないということが起きたりします。これを解決するために用意されているのが遅延環境変数(enabledelayedexpansion)です。

例えば複数のファイルを bat ファイルにドラッグアンドドロップして、そのファイルを1つずつ処理したいという場合には for を使って以下のように書くことができますが、enabledelayedexpansion を書き忘れたりとか変数の展開に % と ! の使い分けが必要だったりとか、いろいろと面倒です。

@echo off cd /d %~dp0 setlocal enabledelayedexpansion for %%f in (%*) do ( set old=%%~dpnxf set new=!old:AAA=BBB! echo old: !old! echo new name: !new! ) endlocal pause exit /b 0

例えばこの bat に3つのファイル(AAA.txt, AAA2.txt, AAA3.txt)をドラッグアンドドロップすると以下のようになります。
(パス内の AAA を BBB に置換して出力)

old: C:\Path\to\AAA.txt new name: C:\Path\to\BBB.txt old: C:\Path\to\AAA2.txt new name: C:\Path\to\BBB2.txt old: C:\Path\to\AAA3.txt new name: C:\Path\to\BBB3.txt Press any key to continue . . .

これを enabledelayedexpansion を使わないで書き直せないかと思って試行錯誤してみたところ、サブルーチンを使うと上手く書けることがわかりました。例えば先ほどの処理と同じものは以下のように書けます。サブルーチンは for の行内とはみなされないので、enabledelayedexpansion がなくてもちゃんと変数展開されます。

@echo off cd /d %~dp0 for %%f in (%*) do ( call :internal "%%~dpnxf" ) pause exit /b 0 :::実際の処理はこっちに書く :internal set old=%~1 set new=%old:AAA=BBB% echo old: %old% echo new name: %new% exit /b 0

毎回ハマっている気がするので、今度からはこれをひな形にすることにしましょうかね。


    トラックバックについて
    Trackback URL:
    お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
    このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/11244
    Trackbacks
    このエントリにトラックバックはありません
    Comments
    愛のあるツッコミをお気軽にどうぞ。[policy]
    古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
    コメントはありません
    Comments Form

    OpenID を使ってログインすることができます。

    Identity URL: Yahoo! JAPAN IDでログイン