我努力理解for..do
循环语法及其%%
变量的使用。我已经经历了2个具体的例子/实施了其中一个for
循环不使用DELAYEDEXPANSION
,另一个在那里它使用DELAYEDEXPANSION
与!
符号。第一个 for 循环似乎与 Windows XP 等旧操作系统兼容,而第二个 for 循环示例不兼容。
具体来说,第一个 for 循环示例取自此答案(与此相关),第二个 for 循环示例取自此答案。
下面复制了两个示例的修改代码:
第一个 for 循环
for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%"
set "YYYY=%dt:~0,4%"
set "MM=%dt:~4,2%"
set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%"
set "Min=%dt:~10,2%"
set "Sec=%dt:~12,2%"
set "datestamp=%YYYY%%MM%%DD%"
set "timestamp=%HH%%Min%%Sec%"
echo datestamp: "%datestamp%"
echo timestamp: "%timestamp%"
第二个 for 循环
SETLOCAL ENABLEDELAYEDEXPANSION
set "path_of_folder=C:\folderA\folderB"
for /f "skip=5 tokens=1,2,4 delims= " %%a in (
'dir /ad /tc "%path_of_folder%\."') do IF "%%c"=="." (
set "dt=%%a"
set vara=%%a
set varb=%%b
echo !vara!, !varb!
set day=!vara:~0,2!
echo !day!
)
由于我一直在阅读并看到延迟扩展(或!
符号)与旧操作系统(例如 Windows XP)不兼容的问题,我想看看如何像第一个循环一样编写第二个循环;即不使用DELAYEDEXPANSION
.
我详细解释了aschipfl在他的评论中写的已经完全正确的内容。
这两个批处理文件也可在 Windows 2000 和 Windows XP 上使用,也cmd.exe
可用作命令解释器。批处理文件在 MS-DOS、Windows 95 和 Windows 98 上无法使用非常有限command.com
的命令解释器。
可以/?
在命令提示符窗口中使用参数执行命令,以获取此命令的帮助输出。当使用启用的命令扩展编写帮助时,这意味着仅受cmd.exe
基于 Windows NT 的 Windows 版本支持,而不受 MS-DOS 或 Windows 9x 支持,使用command.com
. 这意味着,例如for /F
或if /I
或call :Subroutine
在 Windows 9x 上或在基于 Windows NT 且明确禁用命令扩展的 Windows 上可用。在 Windows 9x 上,甚至无法使用"%~1"
或"%~nx1"
.
第一个批处理文件在FOR循环中只执行1 个命令,恰好 1 次:
set "dt=%%a"
在FOR循环完成后执行下面的所有其他命令。换句话说,第一个批处理文件中的FOR循环不使用命令块在FOR循环内运行多个命令。
每当 Windows NT 命令解释器在命令行上检测到命令块的开头时,它都会在第一次在该命令行上执行命令之前处理整个命令块。
这意味着对于第二个批处理文件%Variable%
,在执行FOR命令之前已经扩展了所有使用的变量引用,然后使用上面FOR命令行定义的变量值执行命令块中的命令。这可以通过@echo off
从批处理文件的第一行中删除或将其更改为@echo ON
并从命令提示符窗口中运行批处理文件来看到,因为现在可以看到哪些命令行和用(
...定义的整个命令块)
在预处理后真正执行通过命令解释器。
因此,无论何时在命令块中定义或修改环境变量并且在同一命令块中引用其值时,都必须使用延迟扩展或使用变通方法。
下面演示了一种解决方法:
setlocal EnableExtensions DisableDelayedExpansion
set "FolderPath=%SystemRoot%\System32"
for /F "skip=5 tokens=1,2,4 delims= " %%a in ('dir /AD /TC "%FolderPath%\."') do if "%%c"=="." (
set "VarA=%%a"
set "VarB=%%b"
call echo %%VarA%%, %%VarB%%
call set "Day=%%VarA:~0,2%%
call echo %%Day%%
)
endlocal
pause
由于@echo off
此批处理代码顶部没有,因此可以在执行批处理文件时看到此处发生的情况。每个%%
都在处理命令块时被修改为%
. 因此执行的是命令行。
call echo %VarA%, %VarB%
call set "Day=%VarA:~0,2%
call echo %Day%
命令CALL用于再次处理行的其余部分以运行ECHO和SET命令,其中环境变量引用被替换为它们的相应值,没有或有字符串替换。
避免延迟扩展的另一种解决方法是使用子例程:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FolderPath=%SystemRoot%\System32"
for /F "skip=5 tokens=1,2,4 delims= " %%a in ('dir /AD /TC "%FolderPath%\."') do if "%%c"=="." call :ProcessCreationDate "%%a" "%%b"
endlocal
pause
goto :EOF
:ProcessCreationDate
echo %~1, %~2
set "Day=%~1"
set "Day=%Day:~0,2%
echo %Day%
goto :EOF
子程序就像嵌入在当前批处理文件中的另一个批处理文件。
第一个goto :EOF
避免了子程序代码的失败。
goto :EOF
如果上面的行是批处理文件的最后一行,则不需要第二行。但是还是建议使用它,以防以后像第二个子程序一样在下面添加更多命令行。
第二个批处理文件用于获取创建指定文件夹的日期。可以在不使用延迟扩展和任何变通方法的情况下对此批处理文件进行编码。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FolderPath=%SystemRoot%\System32"
for /F "skip=5 tokens=1,2,4 delims= " %%a in ('dir /ad /tc "%FolderPath%\." 2^>nul') do if "%%c"=="." set "CreationDate=%%a, %%b" & goto OutputDateAndDay
echo Failed to get creation date of "%FolderPath%"
endlocal
pause
goto :EOF
:OutputDateAndDay
echo %CreationDate%
set "Day=%CreationDate:~0,2%
echo %Day%
endlocal
pause
一旦找到具有指定文件夹创建日期的感兴趣的行,创建日期/时间将分配给环境变量,并使用命令GOTO退出FOR循环以继续在下面的标签上执行。运算符的含义参见使用 Windows 批处理文件的单行多命令。&
此解决方案优于所有其他方法,因为FOR循环仅执行 3 个命令IF、SET和GOTO一次的单个命令行,这使得该解决方案最快。当由于目录根本不存在而无法确定目录的创建日期时,它会输出错误消息。
当然,一旦确定并输出目录的创建日期,也可以在其他解决方案上添加GOTO命令以退出FOR循环。然而,最后一个解决方案是最快的,在我看来,最适合这项任务的解决方案。
顺便说一句:所有发布的批处理文件示例都在 Windows XP 上进行了测试并产生了预期的输出。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句