gpt4 book ai didi

batch-file - 使环境变量在 ENDLOCAL 中存活

转载 作者:行者123 更新时间:2023-12-03 10:23:10 24 4
gpt4 key购买 nike

我有一个批处理文件,它通过一系列中间变量计算变量:

@echo off
setlocal

set base=compute directory
set pkg=compute sub-directory
set scripts=%base%\%pkg%\Scripts

endlocal

%scripts%\activate.bat

最后一行的脚本没有被调用,因为它在 endlocal 之后,它破坏了 scripts环境变量,但它必须在 endlocal 之后,因为它的目的是设置一堆其他环境变量供用户使用。

我如何调用一个脚本,其目的是设置永久环境变量,但谁的位置由临时环境变量确定?

我知道我可以在 endlocal 之前创建一个临时批处理文件并在 endlocal 之后调用它,如果没有其他问题,我会这样做,但我想知道是否有一个不那么令人畏缩的解决方案。

最佳答案

ENDLOCAL & SET VAR=%TEMPVAR%图案很经典。但也有不理想的情况。

如果您不知道 TEMPVAR 的内容,那么如果该值包含特殊字符(如 <),您可能会遇到问题。 > &| .您通常可以通过使用像 SET "VAR=%TEMPVAR%" 这样的引号来防止这种情况发生。 ,但是如果有特殊字符并且值已经被引用,这可能会导致问题。

如果您担心特殊字符,则 FOR 表达式是跨越 ENDLOCAL 屏障传输值的绝佳选择。延迟扩展应在 ENDLOCAL 之前启用,并在 ENDLOCAL 之后禁用。

setlocal enableDelayedExpansion
set "TEMPVAR=This & "that ^& the other thing"
for /f "delims=" %%A in (""!TEMPVAR!"") do endlocal & set "VAR=%%~A"

限制:
  • 如果在 ENDLOCAL 之后启用延迟扩展,那么如果 TEMPVAR 包含 !,最终值将被破坏。 .
  • 无法传输包含换行符的值

  • 如果您必须返回多个值,并且您知道某个字符不能出现在任一值中,那么只需使用适当的 FOR/F 选项。例如,如果我知道这些值不能包含 | :
    setlocal enableDelayedExpansion
    set "temp1=val1"
    set "temp2=val2"
    for /f "tokens=1,2 delims=|" %%A in (""!temp1!"|"!temp2!"") do (
    endLocal
    set "var1=%%~A"
    set "var2=%%~B"
    )

    如果必须返回多个值,并且字符集不受限制,则使用嵌套的 FOR/F 循环:
    setlocal enableDelayedExpansion
    set "temp1=val1"
    set "temp2=val2"
    for /f "delims=" %%A in (""!temp1!"") do (
    for /f "delims=" %%B in (""!temp2!"") do (
    endlocal
    set "var1=%%~A"
    set "var2=%%~B"
    )
    )

    一定要退房 jeb's answer一种安全、防弹的技术,适用于所有情况下的所有可能值。

    2017-08-21 - 新功能 RETURN.BAT
    我曾与 DosTips 用户 jeb 合作开发 a batch utility called RETURN.BAT可用于退出脚本或被调用的例程并跨越 ENDLOCAL 屏障返回一个或多个变量。很酷 :-)

    下面是代码的 3.0 版。我很可能不会更新此代码。最好按照链接确保您获得最新版本,并查看一些示例用法。

    RETURN.BAT
    ::RETURN.BAT Version 3.0
    @if "%~2" equ "" (goto :return.special) else goto :return
    :::
    :::call RETURN ValueVar ReturnVar [ErrorCode]
    ::: Used by batch functions to EXIT /B and safely return any value across the
    ::: ENDLOCAL barrier.
    ::: ValueVar = The name of the local variable containing the return value.
    ::: ReturnVar = The name of the variable to receive the return value.
    ::: ErrorCode = The returned ERRORLEVEL, defaults to 0 if not specified.
    :::
    :::call RETURN "ValueVar1 ValueVar2 ..." "ReturnVar1 ReturnVar2 ..." [ErrorCode]
    ::: Same as before, except the first and second arugments are quoted and space
    ::: delimited lists of variable names.
    :::
    ::: Note that the total length of all assignments (variable names and values)
    ::: must be less then 3.8k bytes. No checks are performed to verify that all
    ::: assignments fit within the limit. Variable names must not contain space,
    ::: tab, comma, semicolon, caret, asterisk, question mark, or exclamation point.
    :::
    :::call RETURN init
    ::: Defines return.LF and return.CR variables. Not required, but should be
    ::: called once at the top of your script to improve performance of RETURN.
    :::
    :::return /?
    ::: Displays this help
    :::
    :::return /V
    ::: Displays the version of RETURN.BAT
    :::
    :::
    :::RETURN.BAT was written by Dave Benham and DosTips user jeb, and was originally
    :::posted within the folloing DosTips thread:
    ::: http://www.dostips.com/forum/viewtopic.php?f=3&t=6496
    :::
    ::==============================================================================
    :: If the code below is copied within a script, then the :return.special code
    :: can be removed, and your script can use the following calls:
    ::
    :: call :return ValueVar ReturnVar [ErrorCode]
    ::
    :: call :return.init
    ::

    :return ValueVar ReturnVar [ErrorCode]
    :: Safely returns any value(s) across the ENDLOCAL barrier. Default ErrorCode is 0
    setlocal enableDelayedExpansion
    if not defined return.LF call :return.init
    if not defined return.CR call :return.init
    set "return.normalCmd="
    set "return.delayedCmd="
    set "return.vars=%~2"
    for %%a in (%~1) do for /f "tokens=1*" %%b in ("!return.vars!") do (
    set "return.normal=!%%a!"
    if defined return.normal (
    set "return.normal=!return.normal:%%=%%3!"
    set "return.normal=!return.normal:"=%%4!"
    for %%C in ("!return.LF!") do set "return.normal=!return.normal:%%~C=%%~1!"
    for %%C in ("!return.CR!") do set "return.normal=!return.normal:%%~C=%%2!"
    set "return.delayed=!return.normal:^=^^^^!"
    ) else set "return.delayed="
    if defined return.delayed call :return.setDelayed
    set "return.normalCmd=!return.normalCmd!&set "%%b=!return.normal!"^!"
    set "return.delayedCmd=!return.delayedCmd!&set "%%b=!return.delayed!"^!"
    set "return.vars=%%c"
    )
    set "err=%~3"
    if not defined err set "err=0"
    for %%1 in ("!return.LF!") do for /f "tokens=1-3" %%2 in (^"!return.CR! %% "") do (
    (goto) 2>nul
    (goto) 2>nul
    if "^!^" equ "^!" (%return.delayedCmd:~1%) else %return.normalCmd:~1%
    if %err% equ 0 (call ) else if %err% equ 1 (call) else cmd /c exit %err%
    )

    :return.setDelayed
    set "return.delayed=%return.delayed:!=^^^!%" !
    exit /b

    :return.special
    @if /i "%~1" equ "init" goto return.init
    @if "%~1" equ "/?" (
    for /f "tokens=* delims=:" %%A in ('findstr "^:::" "%~f0"') do @echo(%%A
    exit /b 0
    )
    @if /i "%~1" equ "/V" (
    for /f "tokens=* delims=:" %%A in ('findstr /rc:"^::RETURN.BAT Version" "%~f0"') do @echo %%A
    exit /b 0
    )
    @>&2 echo ERROR: Invalid call to RETURN.BAT
    @exit /b 1


    :return.init - Initializes the return.LF and return.CR variables
    set ^"return.LF=^

    ^" The empty line above is critical - DO NOT REMOVE
    for /f %%C in ('copy /z "%~f0" nul') do set "return.CR=%%C"
    exit /b 0

    关于batch-file - 使环境变量在 ENDLOCAL 中存活,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3262287/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com