68

我做了这个代码

dir /B /S %RepToRead% > %FileName%

for /F "tokens=*" %%a in ('type %FileName%') do (
    set z=%%a
    echo %z%
    echo %%a
)

echo %%a工作正常,但echo %z%返回“回声禁用”。

我需要设置一个 %z% 因为我想像这样拆分变量%z:~7%

有任何想法吗?

4

10 回答 10

92

在 for 循环和括号范围内设置和使用变量有两种方法。

  1. setlocal enabledelayedexpansionsetlocal /?寻求帮助。这仅适用于 XP/2000 或更新版本的 Windows。然后在循环内使用!variable!而不是...%variable%

  2. 使用批处理 goto labels 创建批处理函数:Label

    例子:

    for /F "tokens=*" %%a in ('type %FileName%') do call :Foo %%a
    goto End
    
    :Foo
    set z=%1
    echo %z%
    echo %1
    goto :eof
    
    :End
    

    批处理函数是非常有用的机制。

于 2012-12-10T21:47:52.097 回答
55

你可能想要SETLOCAL ENABLEDELAYEDEXPANSION. 有关详细信息,请参阅https://devblogs.microsoft.com/oldnewthing/20060823-00/?p=29993

基本上:正常%variables%cmd.exe读取命令后立即展开。在您的情况下,“命令”是全部

for /F "tokens=*" %%a in ('type %FileName%') do (
    set z=%%a
    echo %z%
    echo %%a
)

环形。那时z还没有价值,所以echo %z%变成echo. 然后循环被执行并被z设置,但它的值不再被使用。

SETLOCAL ENABLEDELAYEDEXPANSION启用附加语法,!variable!. 这也扩展了变量,但它仅在执行每个(子)命令之前才这样做。

SETLOCAL ENABLEDELAYEDEXPANSION
for /F "tokens=*" %%a in ('type %FileName%') do (
    set z=%%a
    echo !z!
    echo %%a
)

z这为您提供了每次运行的当前值echo

于 2012-12-10T16:54:30.197 回答
12

我为此奋斗了好几个小时。这是我注册命令行变量的循环。示例:Register.bat /param1:value1 /param2:value2

它的作用是循环所有命令行参数,并将具有正确名称的变量设置为值。

之后,您可以使用 set value=!param1! 设置 value2=!param2!

无论给出参数的顺序。(所谓的命名参数)。注意 !<>!,而不是 %<>%。

SETLOCAL ENABLEDELAYEDEXPANSION

FOR %%P IN (%*) DO (
    call :processParam %%P
)

goto:End

:processParam [%1 - param]

    @echo "processparam : %1"
    FOR /F "tokens=1,2 delims=:" %%G IN ("%1") DO (
        @echo a,b %%G %%H
        set nameWithSlash=%%G
        set name=!nameWithSlash:~1!
        @echo n=!name!
        set value=%%H
        set !name!=!value!
    )
    goto :eof

:End    
于 2014-11-23T20:35:14.563 回答
3

使用 %var%、!var! 和 %% 的批处理代码的简单示例。

在这个示例代码中,这里的重点是我们要使用内置变量 TIME 来捕获开始时间(使用时间,因为它总是自动更改):

代码:

@echo off
setlocal enabledelayedexpansion
SET "SERVICES_LIST=MMS ARSM MMS2"
SET START=%TIME%
SET "LAST_SERVICE="

for %%A in (%SERVICES_LIST%) do (
    SET START=!TIME!
    CALL :SOME_FUNCTION %%A
    SET "LAST_SERVICE=%%A"
    ping -n 5 127.0.0.1 > NUL
    SET OTHER=!START!
    if !OTHER! EQU !START! (
    echo !OTHER! is equal to !START! as expected
    ) ELSE (
    echo NOTHING
    )
)
ECHO Last service run was %LAST_SERVICE%

:: Function declared like this
:SOME_FUNCTION
echo Running: %1
EXIT /B 0

代码评论:

  • 使用 enabledelayedexpansion
  • 前三行 SET 是 SET 命令的典型用法,大部分时间都使用它。
  • 下一行是一个 for 循环,必须使用 %%A 进行迭代,然后 %%B 如果里面有循环等等。你不能使用长变量名。
  • 要访问已更改的变量,例如时间变量,您必须使用 !! 或设置 !! (已启用延迟扩展)。
  • 在 for 循环中循环时,每次迭代都作为 %%A 变量访问。
  • for 循环中的代码指出了设置变量的各种方法。查看“SET OTHER=!START!”,如果您要更改为 SET OTHER=%START%,您会明白为什么!是需要的。(提示:你不会看到任何东西)输出。
  • 简而言之 !!更可能在循环内部需要,通常 %var% , %% 总是一个 for 循环。

进一步阅读

使用以下链接更详细地确定原因:

于 2020-04-30T16:32:00.860 回答
2

为了扩展答案,我来到这里以获得更好的理解,所以我写了这个可以解释它并帮助我。

setlocal DisableDelayedExpansion在里面有,所以你可以在setlocal EnableDelayedExpansion它和它之间根据需要在本地设置它。

@echo off
title %~nx0
for /f "tokens=*" %%A in ("Some Thing") do (
  setlocal EnableDelayedExpansion
  set z=%%A
  echo !z!        Echoing the assigned variable in setlocal scope.
  echo %%A        Echoing the variable in local scope.
  setlocal DisableDelayedExpansion
  echo !z!        &rem !z!           Neither of these now work, which makes sense.
  echo %z%        &rem ECHO is off.  Neither of these now work, which makes sense.
  echo %%A        Echoing the variable in its local scope, will always work.
  )
于 2020-01-25T18:34:50.547 回答
1
set list = a1-2019 a3-2018 a4-2017
setlocal enabledelayedexpansion
set backup=
set bb1=

for /d %%d in (%list%) do (
   set td=%%d
   set x=!td!
   set y=!td!
   set y=!y:~-4!
   if !y! gtr !bb1! (
     set bb1=!y!
     set backup=!x!
   )
)

rem: backup will be 2019
echo %backup% 
于 2019-09-11T07:06:34.677 回答
0

如果您访问范围之外的变量,则可以使用宏

@echo off
::Define macro
set "sset=set"

for /l %%a in (1,1,4) do (
    ::set in loop
    %sset% /a "x[%%a]=%%a*%%a"
    
    if %%a equ 4 (
        :: set in condition
        %sset% "x[%%a]=x Condition"
        %sset% "y=y Condition"
    )
)

echo x1=%x[1]%  x2=%x[2]%  x3=%x[3]%  x4=%x[4]%  y=%y%

:: Bonus. enableDelayedExpansion used to access massive from the loop
setlocal enableDelayedExpansion

echo Echo from the loop
for /l %%a in (1,1,4) do (
    ::echo in one line - echo|set /p =
    echo|set /p "=x%%a=!x[%%a]!  "
    if %%a equ 4 echo y=%y%
)
pause
于 2021-11-27T09:37:16.190 回答
-2

尝试这个:

setlocal EnableDelayedExpansion

...

for /F "tokens=*" %%a in ('type %FileName%') do (
    set z=%%a
    echo !z!
    echo %%a
)
于 2017-02-03T11:51:04.450 回答
-3

我知道这不是所要求的,但是当我尝试在“循环”中设置变量时,我从这种方法中受益。使用数组。替代实施选项。

SETLOCAL ENABLEDELAYEDEXPANSION

...

set Services[0]=SERVICE1
set Services[1]=SERVICE2
set Services[2]=SERVICE3

set "i=0"

:ServicesLoop
if defined Services[%i%] (
    set SERVICE=!Services[%i%]!

    echo CurrentService: !SERVICE!

    set /a "i+=1"
    GOTO :ServicesLoop
)
于 2018-07-06T09:25:47.563 回答
-4

以下应该有效:

setlocal EnableDelayedExpansion
for /F "tokens=*" %%a in ('type %FileName%') do (
    set "z=%%a"
    echo %z%
    echo %%a
)
于 2015-06-08T11:40:26.063 回答