0

2 つの Windows バッチ スクリプトがあります。最初のものは2番目のものを呼び出します。ただし、FOR ループでは ENABLEDELAYEDEXPANSION が必要なため、2 番目のバッチ スクリプトの呼び出しの前後で SETLOCAL を使用する必要があります。

=== batch1.bat

@echo off
echo in %0
set BAT1_VAR=5
SETLOCAL
    call  batch2.bat
    set|find "BAT"
    echo === before endlocal
ENDLOCAL
set|find "BAT"
echo === after endlocal
echo === begin exiting %0
set|find "BAT"
echo === end exiting %0
exit /B 0

=== batch2.bat

@echo off
echo in %0
SET BAT2_VAR=7
echo === begin exiting %0
SET|FIND "BAT"
echo === end exiting %0
EXIT /B 0

=== 問題は、batch2.bat によって設定された変数が、batch1.bat に戻った後も存在している必要があることです。これは、次を使用して解決できます。

ENDLOCAL & set BAT2_VAR=%BAT2_VAR%

ただし、batch1.bat が、batch2.bat によって作成された変数の名前を知る必要はありません。多くの場合があり、リストは変更される可能性があります。

この問題を克服するためのアイデアはありますか? ありがとう。

4

1 に答える 1

8

ループ内、または括弧で囲まれたコード ブロック内にいる場合は、ENDLOCAL & set BAT2_VAR=%BAT2_VAR%メソッドを使用できません。

このようなものは失敗します

REM delayed expansion is disabled to start
for ... %%A in (....) do (
   REM must SET before enabling delayed expansion to preserve ! in %%A value
   set var=%%A
   REM the remainder of the loop needs delayed expansion
   setlocal enableDelayedExpansion
   REM do something with !var!
   call batch2 !var!
   REM maybe the batch2 modifies var some more
   REM Must endlocal and preserve the value. The attempt below fails because %var% will
   REM be the value that existed before the loop was entered
   endlocal & set "var=%var%"
)

簡単な修正は、FOR 変数を介して値を転送することです。

REM delayed expansion is disabled to start
for ... %%A in (....) do (
   REM must SET before enabling delayed expansion to preserve ! in %%A value
   set var=%%A
   REM the remainder of the loop needs delayed expansion
   setlocal enableDelayedExpansion
   REM do something with !var!
   call batch2 !var!
   REM maybe the batch2 modifies var some more
   REM the code below successfully transports the value across the endlocal barrier
   for /f "delims=" %%B in ("!var!") do endlocal & set "var=%%B"
)

あなたのバッチは、保持する必要がある多くの値を設定する可能性があると言います。通常、戻り変数の名前を CALLed ルーチンに渡すと、ルーチンは次のようになります。

set "%~2=return value1"
set "%~3=return value2"
... etc.

すべての変数の名前はわかっていますが、endlocal バリアを越えてすべての値を転送するには、多くのコードが必要になる場合があります。

すべての変数に共通のプレフィックスを付けてから、FOR /F ループを使用して値を保持することができます。FOR /F ('コマンド') の結果セット全体は、反復が開始される前にキャッシュされます。

呼び出されたバッチは、変数、、...を設定できprefix.var1prefix.var2prefix.varNのコードが機能します

REM delayed expansion is disabled to start
for ... %%A in (....) do (
   REM must SET before enabling delayed expansion to preserve ! in %%A value
   set var=%%A
   REM the remainder of the loop needs delayed expansion
   setlocal enableDelayedExpansion
   REM do something with !var!
   call batch2 !var! prefix.
   REM the batch2 set variables prefixed by prefix.
   REM Must endlocal and preserve all values.
   for /f "delims=" %%B in ('set prefix.') do (
     if "!"=="" endlocal
     set "%%B"
   )
)

このif "!"=="" endlocal行は、最初の内部ループ反復でのみ endlocal を実行するための巧妙なトリックです。これは、外側のループの前に遅延展開が無効になり、各外側のループ反復の上部近くで有効になったという事実に依存しています。

于 2012-12-07T22:27:56.013 に答える