如何在 /F 的循环内设置变量
Posted
技术标签:
【中文标题】如何在 /F 的循环内设置变量【英文标题】:How to set a variable inside a loop for /F 【发布时间】:2021-06-02 22:31:06 【问题描述】:我编写了这段代码
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%
这样拆分变量
有什么想法吗?
【问题讨论】:
我认识到这并不能直接回答问题,但也许解决方案是切换到像 powershell 或 bash 这样的健全的脚本语言 Batch script for loop won't set variable的可能重复 【参考方案1】:有两种方法可以在 for 循环和括号范围内设置和使用变量。
setlocal enabledelayedexpansion
请参阅setlocal /?
寻求帮助。这仅适用于 XP/2000 或更新版本的 Windows。
然后在循环内使用!variable!
而不是%variable%
...
使用批处理 goto 标签 :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
批处理函数是非常有用的机制。
【讨论】:
double %% 是在 .bat 文件中运行它而不是直接在命令行中运行的问题。 这就是我讨厌批处理的原因 当你需要做一些字符串替换时(比如here),这个标签方法很有效。我无法使用 ENABLEDELAYEDEXPANSION 进行替换。 是的,这就是我们都讨厌语法的原因【参考方案2】:你可能想要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
)
这会在每次echo
运行时为您提供z
的当前值。
【讨论】:
你是对的。我通过使用 echo !z! 找到了解决方案!并在顶部添加 setlocal enablelayedexpansion【参考方案3】:我为此奋斗了好几个小时。 这是我注册命令行变量的循环。 示例:Register.bat /param1:value1 /param2:value2
它的作用是循环所有命令行参数, 并将具有正确名称的变量设置为值。
之后,您可以使用 设置值=!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
【讨论】:
谢谢。我试图在 for 循环中进行子字符串检测,而其他示例没有这个有用。【参考方案4】:使用 %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%,您会明白为什么!是需要的。 (提示:您将看到 NOTHING)输出。 简而言之!更可能需要在循环内部,通常为 %var%,%% 始终是 for 循环。进一步阅读
使用以下链接更详细地确定原因:
Difference between %variable% and !variable! in batch file Variable usage in batch file【讨论】:
【参考方案5】: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%
【讨论】:
【参考方案6】:为了扩展答案,我来这里是为了更好地理解,所以我写了这个可以解释它并帮助我。
其中有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.
)
【讨论】:
【参考方案7】:如果您访问范围之外的变量,则可以使用宏
@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
【讨论】:
【参考方案8】:试试这个:
setlocal EnableDelayedExpansion
...
for /F "tokens=*" %%a in ('type %FileName%') do (
set z=%%a
echo !z!
echo %%a
)
【讨论】:
【参考方案9】:我知道这不是所要求的,但是当我尝试在“循环”中设置变量时,我从这种方法中受益。使用数组。替代实施选项。
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
)
【讨论】:
【参考方案10】:以下应该有效:
setlocal EnableDelayedExpansion
for /F "tokens=*" %%a in ('type %FileName%') do (
set "z=%%a"
echo %z%
echo %%a
)
【讨论】:
这行不通。这正是 OP 发布的无效以上是关于如何在 /F 的循环内设置变量的主要内容,如果未能解决你的问题,请参考以下文章
我将如何隔离或仅将第二个元素存储在批处理文件内的 for 循环中?