括弧で囲まれたブロック内のすべてのコードは、1 回のパスで解析されます。パーセンテージを使用した通常の変数展開は、解析時に発生します。したがって、ブロック内に変数を設定すると、その値はブロックに入る前に存在していた値になるため、正規展開を使用して値にアクセスすることはできません。
上記の状況があります。問題を解決するには、2 つの古典的な方法があります。
1) CALL を使用して、行ったようにパーセントを 2 倍にすることができます。CALL は、呼び出された行に対して通常の展開が 2 回発生するため、問題を解決します。ブロック全体に対して 1 回、行が実行される前に、ブロック内の前の行が実行された後にもう一度実行されます。最初の展開ではダブル パーセントがシングル パーセントに変換され、2 番目の展開では実際に変数が展開されます。
私はこの解決策が好きではありません。なぜなら、それは遅いからです。また、CALL が引用符で囲まれた^
文字に問題を引き起こすためです。
同じコマンドで複数の CALL を使用できます。各コールでは、パーセントを 2 倍にする必要があります。したがって、1 回の CALL には 2 パーセント、2 回の CALL には 4 パーセント、3 回の CALL には 8 パーセントが必要です。
2) 推奨される解決策は、遅延展開を使用することだと思います。これははるかに高速であり、遅延展開を使用したときに、、、、などの特殊&
文字をエスケープまたは引用することを心配する必要もありません。遅延展開は、まさにそのとおりです。変数は、行が実行される直前まで展開されません。遅延拡張は、使用する前に有効にする必要があります。バッチ ファイル内では、.|
>
<
setlocal enableDelayedExpansion
遅延展開で発生する可能性のある問題の 1 つは、FOR 変数が含まれていると破損し、!
展開時に遅延展開が有効になることです。これは通常、ループ内で遅延展開のオンとオフを切り替えることで解決できます。
コマンド プロンプトから入力HELP SET
すると、コード ブロック内で変数を展開する際の問題と、遅延展開がどのように役立つかについてのかなり適切な説明が表示されます。説明は、単語で約半分下に始まりますFinally, support for delayed environment variable expansion...
。
注 - SET /A 計算内で使用する場合、変数を展開する必要はありません。SET /A は、実行時に値を自動的に展開します。未定義の変数はゼロとして扱われます。
コードでは、単に使用できますset /a add=add+1
しかし、さらに簡単な省略形の方法があります -+=
演算子を使用できます: set /a add+=1
.
CALL を使用せずにコードを記述する別の方法を次に示します。コードはテストされていませんが、正しく理解できたと思います。
@echo off
setlocal disableDelayedExpansion
cd "%~dp0"
md newfolder
set add=0
for /f "usebackq eol=: delims=" %%F in ("list.txt") do (
set /a add+=1
set "file=%%F"
setlocal enableDelayedExpansion
set "addx=00!add!"
copy "!file!" "newfolder\!addx:~-3!_!file!"
endlocal
)
pause
すでに値が設定されている可能性があるため、明示的add
に 0 に初期化します。未定義であるか、すでに 0 に設定されていることがわかっている場合、初期化は必要ありません。
FOR ループはファイル名を処理しており、ファイル名!
内で有効です。!
これが、ループ内で遅延拡張のオンとオフを切り替える理由です。拡張時にファイル名が破損するのは望ましくありません%%F
。ファイル名が で始まる場合もあります;
(ほとんどありませんが)。存在する場合、デフォルトの EOL 文字が であるため、FOR はそのファイルをスキップします;
。ファイルを で開始することはできないため、代わりに:
EOL を設定するのが好きです。:
バッチ ファイルの完了後に環境変数の定義が保持されないように、SETLOCAL を一番上に配置しました。