2017-07-06 91 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