2017-07-06 61 views
1

在我努力了解for..do循环语法及其使用%%变量。我经历了两个具体的例子/实现,其中一个for循环不使用DELAYEDEXPANSION,另一个使用DELAYEDEXPANSION!记号。 1st for循环似乎与Windows XP等较早的操作系统兼容,而2nd for循环示例则不兼容。修改为不使用批处理脚本中的delayedexpansion

具体地说,第一for循环例如从该answer(这是关系到this)和第二for循环例如采取从该answer服用。

两个例子复制以下修改后的代码:

1 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

+3

延迟扩展功能在Windows XP下可用。无论如何,为了避免它,使用'call echo %% vara %%,%% varb %%'和'call set day = %% vara:〜0.2 %%'这样的调用语法,或者移动主体循环放入一个[子例程](http://ss64.com/nt/call.html)中,通过'call'调用它作为[参数]传递所有相关值(http:ss64.com/nt/ syntax-args.html)并在那里使用普通的'%' - 扩展;参考也[函数的概念](https://ss64.com/nt/syntax-functions.html)... – aschipfl

回答

2

我详细解释了什么aschipfl写在他的评论已绝对正确。

这两个批处理文件也可在Windows 2000和Windows XP上使用,也可使用cmd.exe作为命令解释程序。批处理文件不能在MS-DOS,Windows 95和Windows 98上使用非常有限的command.com作为命令解释程序。

可以在命令提示符窗口中使用参数/?执行命令以获取输出对此命令的帮助。在帮助中写入并启用了命令扩展这意味着仅在基于Windows NT的Windows版本上支持cmd.exe,并且不支持由MS-DOS或Windows 9x使用command.com。这意味着例如for /Fif /Icall :Subroutine在Windows 9x上或在基于Windows NT的Windows上显式禁用命令扩展时不可用。在Windows 9x上,甚至不可能使用"%~1""%~nx1"

第一个批处理文件执行FOR循环只有1命令恰好1次:

set "dt=%%a" 

所有其它命令后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用于处理该行的其余部分的第二时间与不具有或具有字符串替换可以通过相应的值替换环境变量引用运行ECHOSET命令的命令。

另一个解决方法以避免延迟扩展使用子程序:

@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 

一旦与指定的文件夹的创建日期感兴趣的行被找到,创建日期/时间被分配到环境变量和FOR退出循环使用命令GOTO继续执行在下面的标签上。对于&运营商的含义见Single line with multiple commands using Windows batch file

这种解决方案比所有其他方法更好,因为FOR循环执行与3个命令IF单个命令行,SETGOTO只有一个时间,这使得该解决方案是最快的。并且,当无法确定目录的创建日期时,会输出错误消息,因为该目录根本不存在。

当然也有可能还添加了GOTO命令的其他解决方案,一旦目录的创建日期被确定和输出退出FOR循环。尽管如此,最后的解决方案仍然是最快速并且以我的观点来看最适合这项任务的解决方案。

顺便说一句:所有发布的批处理文件的例子都在Windows XP上测试过,并产生了预期的输出。

+0

真棒的答案。学到了很多。谢谢你和@aschipfl的帮助! – Karim