In my efforts to understand the
for..do loops syntax and their use of
%% variables. I have gone through 2 specific examples/implementations where the one
for loop does not use
DELAYEDEXPANSION and another where it does use
DELAYEDEXPANSION with the
! notation. The 1st for loop appears to be compatible with older OSs like the Windows XP whereas the 2nd for loop example does not.
<em>Specifically, the <strong>1st for loop</strong> example is taken from this <a href="https://stackoverflow.com/a/44948574/6003691" rel="nofollow">answer</a> (which is related to <a href="https://stackoverflow.com/a/44929240/6003691" rel="nofollow">this</a>) and the <strong>2nd for loop</strong> example is taken from this <a href="https://stackoverflow.com/a/19131662/6003691" rel="nofollow">answer</a></em>.
Modified code for both examples copied below:
<strong>1st for loop</strong>
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%"
<strong>2nd for loop</strong>
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! )
Since I have been reading and seeing issues where delayed expansion (or the
! notation) is not compatible with older OSs (e.g. Windows XP), I would like to see <strong>how to write the 2nd loop like the 1st loop; i.e. without the use of
I explain in detail what <a href="https://stackoverflow.com/users/5047996/aschipfl" rel="nofollow">aschipfl</a> wrote already absolutely right in his comment.
Both batch files work also on Windows 2000 and Windows XP using also
cmd.exe as command interpreter. The batch files do not work on MS-DOS, Windows 95 and Windows 98 using very limited
command.com as command interpreter.
A command can be executed with parameter
/? in a command prompt window to get output the help for this command. When in help is written <strong>with enabled command extensions</strong> it means supported only by
cmd.exe on Windows NT based Windows versions and not supported by MS-DOS or Windows 9x using
command.com. That means for example
for /F or
if /I or
call :Subroutine are not available on Windows 9x, or on Windows NT based Windows with command extensions explicitly disabled. On Windows 9x it is not even possible to use
The first batch file executes in <strong>FOR</strong> loop only 1 command exactly 1 times:
All other commands below are executed after <strong>FOR</strong> loop finished. In other words the <strong>FOR</strong> loop in first batch file does not use a command block to run multiple commands within the <strong>FOR</strong> loop.
Whenever Windows NT command interpreter detects the beginning of a command block on a command line, it processes the entire command block before executing the command on this command line the first time.
This means for second batch file all variable references using
%Variable% are expanded already before the command <strong>FOR</strong> is executed and the commands in the command block are then executed with the values of the variables as defined above <strong>FOR</strong> command line. This can be seen by removing
@echo off from first line of batch file or change it to
@echo ON and run the batch file from within a command prompt window because now it can be seen which command lines respectively entire command blocks defined with
) are really executed after preprocessing by command interpreter.
So whenever an environment variable is defined or modified within a command block and its value is referenced in same command block it is necessary to use delayed expansion or use workarounds.
One workaround is demonstrated below:
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
As there is no
@echo off at top of this batch code it can be seen on executing the batch file what happens here. Each
%% is modified on processing the command block to just
%. So executed are the command lines.
call echo %VarA%, %VarB% call set "Day=%VarA:~0,2% call echo %Day%
The command <strong>CALL</strong> is used to process the rest of the line a second time to run the <strong>ECHO</strong> and the <strong>SET</strong> commands with environment variable references replaced by their corresponding values without or with string substitution.
Another workaround to avoid delayed expansion is using a subroutine:
@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
A subroutine is like another batch file embedded in current batch file.
goto :EOF avoids a fall through to the code of the subroutine.
goto :EOF would not be necessary if the line above is the last line of the batch file. But it is recommended to use it nevertheless in case of more command lines are ever added later below like a second subroutine.
The second batch file is for getting the day on which the specified folder was created. It would be possible to code this batch file without usage of delayed expansion and any workarounds.
@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
Once the line of interest with the creation date of specified folder is found, the creation date/time is assigned to an environment variable and the <strong>FOR</strong> loop is exited with using command <strong>GOTO</strong> to continue execution on a label below. For the meaning of
& operator see <a href="https://stackoverflow.com/a/25344009/3074564" rel="nofollow">Single line with multiple commands using Windows batch file</a>.
This solution is better than all other methods because the <strong>FOR</strong> loop executes the single command line with the 3 commands <strong>IF</strong>, <strong>SET</strong> and <strong>GOTO</strong> only one times which makes this solution the fastest. And it outputs an error message when it was not possible to determine the creation date of the directory because the directory does not exist at all.
Of course it would be possible to add a <strong>GOTO</strong> command also on the other solutions to exit <strong>FOR</strong> loop once the creation date of the directory was determined and output. The last solution is nevertheless the fastest and in my point of view best one for this task.
BTW: All posted batch file examples were tested on Windows XP and produced the expected output.