【问题标题】:Return Multiple Variables Dynamically from SETLOCAL从 SETLOCAL 动态返回多个变量
【发布时间】:2014-03-11 05:13:25
【问题描述】:

我试图弄清楚如何以一种相当动态的方式返回多个变量,我只维护一个变量名列表,然后使用循环执行ENDLOCAL“导出”,但似乎!%%V!内部 FOR 循环中的扩展没有足够快地扩展。

有什么我遗漏的东西还是有其他方法可以做到这一点?

示例代码:

SETLOCAL EnableExtensions EnableDelayedExpansion
[...]
SET "RETURN=FOO BAR"
[...]
SET "RETURN=%RETURN% BAZ"
[...]

:END

:: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
ENDLOCAL & (
   FOR %%N IN (%RETURN%) DO (
      FOR /f %%V in ("%%N") DO SET %%N=!%%V!
   )
)

   EXIT /B

感谢您的帮助。

【问题讨论】:

    标签: variables batch-file dynamic return


    【解决方案1】:

    这是一个 return 例程,用于跨范围保留变量。只需使用变量名称作为参数调用返回例程,然后调用endlocal %return%

    常规:

    :return [Variables...]
    setlocal enabledelayedexpansion
    set "return="
    :_return
    if "%~1"=="" endlocal & exit /b 1
    if not defined %~1 goto __return
    set "%~1=!%~1:"=""!"
    set "%~1=!%~1:^=^^!"
    set "%~1=!%~1:<=^<!"
    set "%~1=!%~1:>=^>!"
    set "%~1=!%~1:&=^&!"
    set "%~1=!%~1:|=^|!"
    :__return
    set "return=!return!^&set ""%~1=!%~1!"""
    if not "%~2"=="" shift & goto _return
    setlocal disabledelayedexpansion
    set "return=%return:!=^^^^^^^!%"
    endlocal & endlocal & set "return=%return:""="%"
    exit /b 0
    

    用法:

    call :return foo bar baz
    endlocal %return%
    

    示例:

    只有变量a 会被保留在范围之外。

    @echo off
    setlocal
    echo Inside
    set "a=1"
    set "b=2"
    echo(%a%
    echo(%b%
    call :return a
    endlocal %return%
    echo Outside
    echo(%a%
    echo(%b%
    exit /b 0
    
    :return [Variables...]
    setlocal enabledelayedexpansion
    set "return="
    :_return
    if "%~1"=="" endlocal & exit /b 1
    if not defined %~1 goto __return
    set "%~1=!%~1:"=""!"
    set "%~1=!%~1:^=^^!"
    set "%~1=!%~1:<=^<!"
    set "%~1=!%~1:>=^>!"
    set "%~1=!%~1:&=^&!"
    set "%~1=!%~1:|=^|!"
    :__return
    set "return=!return!^&set ""%~1=!%~1!"""
    if not "%~2"=="" shift & goto _return
    setlocal disabledelayedexpansion
    set "return=%return:!=^^^^^^^!%"
    endlocal & endlocal & set "return=%return:""="%"
    exit /b 0
    

    代码中的问题

    至于为什么你的代码没有按预期工作,是因为必须在运行 endlocal 命令之前扩展变量。阅读这篇关于托管命令行解析批处理脚本的优秀 SO 帖子:Answer:How does the Windows Command Interpreter (CMD.EXE) parse scripts?

    更新

    【讨论】:

    • 谢谢。这确实有效,但如果变量的内容包含一个&符号,它确实会失败,我看到 SET 命令的输出被转储了。
    • @szr 感谢您引起我的注意。与号问题现在应该与其他一些特殊字符一起修复。
    • 谢谢,差不多了。与SET "a=I like M&amp;Ms" 一起工作正常,但我仍然得到一个带有SET "a=I like M^&amp;Ms" 的SET-dump,其中& 用插入符号转义。
    • @szr 添加了对^ 字符的支持。
    • 看起来不错。此外,将循环的结尾更改为 this 将允许具有未定义/空值的变量取消设置上游计数器部分,从而实现更真实的导出。 :) 再次感谢。
    【解决方案2】:
    :: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
    for %%a in ("endlocal" "FOO=%FOO%" "BAR=%BAR%" "BAZ=%BAZ%") do (
       if %%a equ "endlocal" (endlocal) else set %%a
    )
    exit /B
    

    【讨论】:

    • 谢谢,虽然我追求的是一种无需在 FOR 循环中对变量进行硬编码的方法,而是使用包含所需信息的变量。
    【解决方案3】:

    怎么样

    @ECHO OFF
    SETLOCAL
    FOR %%i IN (foo bar baz) DO SET $%%i=value:%%i
    ECHO == initial values ===
    SET $
    SET "RETURN=$FOO $BAR"
    CALL :demo
    ECHO == after CALL modifying %return% ===
    SET $
    
    FOR %%i IN (foo bar baz) DO SET $%%i=value:%%i
    ECHO == initial values ===
    SET $
    
    SET "RETURN=%RETURN% $BAZ"
    CALL :demo
    ECHO == after CALL modifying %return% ===
    SET $
    
    GOTO :eof
    
    :demo
    SETLOCAL ENABLEDELAYEDEXPANSION
    FOR %%i IN (foo bar baz) DO SET $%%i=modified:%%i
    SET "$retvals="
    FOR %%N IN (%RETURN%) DO SET "$retvals=!$retvals!^&set %%N=%%%%N%%"
    CALL SET "$retvals=%$retvals%"
    
    :: "Export" %FOO%, %BAR%, and %BAZ% to calling context.
    endlocal%$retvals%
    
    EXIT /B
    GOTO :EOF
    

    产量

    == initial values ===
    $bar=value:bar
    $baz=value:baz
    $foo=value:foo
    == after CALL modifying $FOO $BAR ===
    $bar=modified:bar
    $baz=value:baz
    $foo=modified:foo
    == initial values ===
    $bar=value:bar
    $baz=value:baz
    $foo=value:foo
    == after CALL modifying $FOO $BAR $BAZ ===
    $bar=modified:bar
    $baz=modified:baz
    $foo=modified:foo
    

    (为了方便显示,我只是使用set更改了变量名)

    【讨论】:

    • 需要注意的一点是call set 有一个很大的警告和性能影响,因为call 命令将解析工作目录和整个PATH 变量在每个目录中搜索@987654327 @PATHEXT 在调用 set 命令之前。此外,如果找到任何set&lt;PATHEXT&gt;,那么它们将被调用而不是实际的set 命令。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    • 2012-04-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多