我详细解释了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
. 这意味着例如在 Windows 9xfor /F
或基于 Windows NT 且命令扩展被明确禁用的 Windows 上不可用if /I
。call :Subroutine
在 Windows 9x 上,甚至无法使用"%~1"
或"%~nx1"
.
第一个批处理文件在FOR循环中仅执行 1 个命令,恰好 1 次:
set "dt=%%a"
下面的所有其他命令都在FOR循环完成后执行。换句话说,第一个批处理文件中的FOR循环不使用命令块在FOR循环中运行多个命令。
每当 Windows NT 命令解释器在命令行上检测到命令块的开头时,它会在第一次执行此命令行上的命令之前处理整个命令块。
这意味着对于第二个批处理文件,所有使用的变量引用在执行命令FOR%Variable%
之前已经展开,然后使用上面定义的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 上进行了测试,并产生了预期的输出。