I have a batch file that looks like the following:
For /f "tokens=2-4 delims=/ " %a in ('date /t') do (set newdate=%c%a%b)
blat my_file_%newdate% -to test#email.com -f test_email.com
When I enter this two commands separately in a cmd window, it seems to work perfectly fine, but when placed into a batch file and ran manually, it does not work.
Open a command prompt window and run for /?. Output is the help for this command containing at top the information:
To use the FOR command in a batch program, specify %%variable instead
of %variable. Variable names are case sensitive, so %i is different from %I.
Next I suggest to run set /? and read at least last page of output help listing the environment variable DATE.
If Command Extensions are enabled, then there are several dynamic
environment variables that can be expanded but which don't show up
in the list of variables displayed by SET. These variable values are
computed dynamically each time the value of the variable is expanded.
If the user explicitly defines a variable with one of these names, then
that definition will override the dynamic one described below:
%CD% - expands to the current directory string.
%DATE% - expands to current date using same format as DATE command.
%TIME% - expands to current time using same format as TIME command.
%RANDOM% - expands to a random decimal number between 0 and 32767.
%ERRORLEVEL% - expands to the current ERRORLEVEL value
%CMDEXTVERSION% - expands to the current Command Processor Extensions
version number.
%CMDCMDLINE% - expands to the original command line that invoked the
Command Processor.
%HIGHESTNUMANODENUMBER% - expands to the highest NUMA node number
on this machine.
So there is perhaps no need to run in a separate command process in background with cmd.exe /C the command line date /T as done by FOR with the posted command line, capture output of this command process, and process it line by line by FOR.
Well, the format of date output by date /T or on using %DATE% depends on Windows region setting. And it was not posted what is the date format on used machine with used account. But I suppose that following works also a very little bit faster.
for /F "tokens=2-4 delims=/ " %%a in ("%DATE%") do set "newdate=%%c%%a%%b"
I suppose using only string substitution works also on your machine for your account with a date format MM/dd/yyyy or dddd, MM/dd/yyyy:
set "newdate=%DATE:~-4%%DATE:~-10,2%%DATE:~-7,2%"
This last solution is some microseconds faster than the others.
There is also a region independent solution as explained in detail for example by the answer on Why does %date% produce a different result in batch file executed as scheduled task? But the region independent solution using WMIC is much slower in comparison to the usage of the dynamic environment variable DATE.
Batch variable need to have %% instead of only one
It appears you are looking for the output to be YYMMDD, if so try this:
For /f "tokens=1-4 delims=/ " %%a in ('date /t') do (set newdate=%%c%%a%%b)
Related
I need to backup an existing folder with date-time stamp and replace it (delete and recreate) with new content inside the folder.
Does anyone have a script to do this?
I tried the following code, where %ApplicationDeploymentFolderPath% = \\servername\foldername
IF EXIST %ApplicationDeploymentFolderPath%\Release (
REM Get current date time
#echo off
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%b_%%a)
For /f "tokens=1-2 delims=/:" %%a in ('time /t') do (set mytime=%%a%%b)
set backup_folder=%mydate%_%mytime%
MD %ApplicationDeploymentFolderPath%\%backup_folder%
REM Copy current folder to backup folder
Copy %ApplicationDeploymentFolderPath%\Release %ApplicationDeploymentFolderPath%\%backup_folder%
REM Delete Existing Release folder
RD %ApplicationDeploymentFolderPath%\Release /S /Q
)
MD %ApplicationDeploymentFolderPath%\Release
The command date with parameter /T outputs the current date in format defined by configured country for current user account. Exactly the same date string can be accessed by referencing dynamic environment variable DATE for example with %DATE%.
The command time with parameter /T outputs the current time in format defined by configured country for current user account. Exactly the same time string can be accessed by referencing dynamic environment variable TIME for example with %TIME%.
What happens on execution of this command line?
For /f "tokens=1-3 delims=/ " %%a in ('date /t') do (set mydate=%%c_%%b_%%a)
for respectively cmd.exe processing the batch file starts in background one more command process using %ComSpec% /c with the command line between '. So executed in background is following with Windows installed in C:\Windows:
C:\Windows\System32\cmd.exe /c date /t
The output of command date to handle STDOUT of this command process in background is captured by FOR respectively Windows command processor instance executing the batch file.
The captured line is split up into three substrings using / as string delimiter assigned to the loop variables a, b and c which are concatenated together in reverse order with underscore as delimiter.
This task can be done much faster by replacing 'date /t' by "%DATE%". In this case FOR processes the date string expanded by already running cmd.exe on parsing this command line before executing FOR. So there is no starting of one more cmd.exe in background and capturing its output just to process the same date string which makes batch file execution a bit faster.
The same is true for 'time /t' which can be replaced by "%TIME%".
But the two FOR loops could be completely optimized away by using string substitution as described for example by answer on What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean? and region dependent date and time format is well known for example by running in a command prompt window:
echo %DATE% %TIME%
This command outputs on my computer with German date/time format according to configured country:
24.07.2019 20:15:29,90
It can be seen on this output that the original code would not work on my Windows computer with my account because of date string contains . and not / and time string contains a comma.
So better would be using a region independent solution as explained very detailed in answer on Why does %date% produce a different result in batch file executed as scheduled task? The disadvantage is that execution of wmic.exe takes much longer than cmd.exe needs to reformat date and time string to yyyy_MM_dd_HHmm. However, the batch file is executed most likely not very often per day, and so it does not really matter if execution to get date/time in this format takes some milliseconds or about one second.
Copying the entire folder is not really necessary in this case. It should be enough to rename it with:
ren "%ApplicationDeploymentFolderPath%\release" "%backup_folder%"
The command move could be also used if command ren cannot be used for unknown reasons.
However, the main problem is missing knowledge about how and when to use delayed expansion. Open a command prompt, run set /? and read the output help explaining on an IF and a FOR example delayed environment variable expansion.
The issue here is that backup_folder is not defined on executing the command lines referencing it with %backup_folder% because of all occurrences of %variable% are replaced by Windows command processor already on parsing entire command block starting here with ( on IF condition at top by current value of the referenced environment variable before executing the command IF.
So executed on existing release folder is:
set backup_folder=
MD \\servername\foldername\
REM Copy current folder to backup folder
Copy \\servername\foldername\Release \\servername\foldername\
REM Delete Existing Release folder
RD \\servername\foldername\Release /S /Q
This can be seen by debugging the batch file.
See also: How does the Windows Command Interpreter (CMD.EXE) parse scripts?
The solution is here avoiding the command block by changing the first IF condition.
Fast region dependent solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ApplicationDeploymentFolderPath=\\servername\foldername"
if not exist "%ApplicationDeploymentFolderPath%\Release\" goto CreateFolder
ren "%ApplicationDeploymentFolderPath%\Release" "%DATE:~-4%_%DATE:~-7,2%_%DATE:~-10,2%_%TIME:~0,2%%TIME:~3,2%"
:CreateFolder
md "%ApplicationDeploymentFolderPath%\Release"
endlocal
Slower region independent solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ApplicationDeploymentFolderPath=\\servername\foldername"
if not exist "%ApplicationDeploymentFolderPath%\Release\" goto CreateFolder
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "BackupDateTime=%%I"
set "BackupDateTime=%BackupDateTime:~0,4%_%BackupDateTime:~4,2%_%BackupDateTime:~6,2%_%BackupDateTime:~8,4%"
ren "%ApplicationDeploymentFolderPath%\Release" "%BackupDateTime%"
:CreateFolder
md "%ApplicationDeploymentFolderPath%\Release"
endlocal
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
ren /?
set /?
setlocal /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
This was inspired by another post on Arqade, on how to backup some files using a batch script.
The following block creates a variable with the current date/time string:
REM -- Get the current date/time stamp
set DS=%date%
set TS=%time: =0%
set mm=%DS:~4,2%
set dd=%DS:~7,2%
set yyyy=%DS:~10,4%
set hh=%TS:~0,2%
set min=%TS:~3,2%
set ss=%TS:~6,2%
set ms=%TS:~9,2%
set DT_STAMP=%yyyy%-%mm%-%dd%_%hh%.%min%.%ss%
As a script writer, it is often convenient to consolidate these down to a single line. However, in this case, condensing this to a single line is extremely difficult, if not impossible.
There does not seem to be a way to put multiple set commands on a single line. Separating commands with & or && works fine, but commands on the right cannot be dependent on variables that were set earlier on the same line.
Also, notice how the time variable must have spaces replaced with zeros 0. There does not seem to be a way to do both a string replacement and get a sub-string on the same line.
Is there any way to get this down to one line? The closest I can get is two lines:
set DS=%date% && set TS=%time: =0%
set DT_STAMP=%DS:~10,4%-%DS:~4,2%-%DS:~7,2%_%TS:~0,2%.%TS:~3,2%.%TS:~6,2%
Update
This has gathered some good answers; allow me to clarify what an accepted answer must have:
An ugly, but re-usable, single line solution is OK (the pretty version is already provided above)
Standard shell commands only (PowerShell and similar must be avoided; if I wanted those, I'd just do the whole thing in PowerShell)
Ability to format the date in any logical format (should be able to do anything the pretty version above can do, not just support ISO formatted dates using shorthand notation)
It is OK to ignore localization settings (really, just this one time!)
Must be on a single line! (for instance, delayed expansion is handy, but can have nasty side-effects, is not re-usable in every context, and usually requires multiple lines)
It's trivial with a FOR /F statement, but as npocmaka already said, it depends on localization.
I assume your date/time looks like
Fri 09/14/2018
8:15:46.12
Then this works
for /F "tokens=1-7 delims=/:,. " %%1 in ("%date% %time: =0%") do set DT_STAMP=%%4-%%2-%%3_%%5.%%6.%%7
But for german localization you need
for /F "tokens=1-7 delims=/:,. " %%1 in ("%date% %time: =0%") do set DT_STAMP=%%3-%%2-%%1_%%4h%%5m%%6s
Solution with a batch macro
You could build a batch macro, the use of macros is more readable, but the macros itself are a bit more complicated
Using the macro, it assigns the current timestamp to the variable myDT1:
%#AssignTimeStamp% myDT1
echo %myDT1%
The definition of the macro (delayed expansion has to be disabled while defining the macro):
REM *** Macro definition, be sure that there aren't any trailing whitespaces
set ^"LF=^
%= This creates a variable containing a single linefeed (0x0A) character =%
^"
:: Define %\M% to effectively issue a newline with line continuation
set ^"\M=^^^%LF%%LF%^%LF%%LF%^^"
set #AssignTimeStamp=for %%. in (1 2) do if %%.==2 (%\M%
%= The next line builds the timestamp =%%\M%
for /F "tokens=1-7 delims=/:,. " %%1 in ("%date% %time: =0%") do set timestamp=%%4-%%2-%%3_%%5h%%6m%%7s%\M%
%= When a variable name was give then store the timestamp there, else output the timestamp =%%\M%
for /F "tokens=1,2 delims=, " %%1 in ("#,!argv!") do ( %\M%
for %%V in (!timestamp!) do endlocal^&if "%%~2" neq "" (set "%%2=%%V") else echo ##%%V%\M%
)%\M%
) else setlocal enableDelayedExpansion^&set argv=,
This can be done as requested using the dynamic environment variables DATE and TIME with date and time being region/country dependent using the command line:
#set "DT_STAMP=%DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2%_%TIME:~0,2%.%TIME:~3,2%.%TIME:~6,2%" & call set "DT_STAMP=%%DT_STAMP: =0%%"
It is expected by this command line that DATE has a date string like Sat 09/15/2018 and TIME has a time string like 4:18:23,56 and is in 24 hours format.
The environment variable DT_STAMP has value 2018-09-15_04.18.23 for the given example date and time strings.
Better would be using the command line:
#set "DT_STAMP=%DATE:~-4%-%DATE:~-10,2%-%DATE:~-7,2%_%TIME:~0,2%.%TIME:~3,2%.%TIME:~6,2%" & call set "DT_STAMP=%%DT_STAMP: =0%%"
This second version has the advantage that it does not matter if date string starts with weekday or not. But date string must have the format MM/dd/yyyy (MDY) with any type of separator like / or . or -.
But most countries use dd.MM.yyyy (DMY) (with different separator) which would require a small modification:
#set "DT_STAMP=%DATE:~-4%-%DATE:~-7,2%-%DATE:~-10,2%_%TIME:~0,2%.%TIME:~3,2%.%TIME:~6,2%" & call set "DT_STAMP=%%DT_STAMP: =0%%"
See also What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean?
The replacement of all spaces by 0 is done on same command line by using a second SET command which references the environment variable DT_STAMP with %% on both sides instead of just %.
The two %% are replaced by cmd.exe during parsing the command line to % before executing the first SET command. So the command line finally executed is for example:
#set "DT_STAMP=2018-09-15_ 4.18.23" & call set "DT_STAMP=%DT_STAMP: =0%"
The usage of CALL results in a second parsing of the command line part after operator & by cmd.exe. Therefore the second SET has as argument "DT_STAMP=2018-09-15_04.18.23" and the environment variable DT_STAMP gets assigned finally the wanted date/time string.
But better would be getting the current local date/time string in wanted format independent on region/country setting which is possible also with a single command line:
#for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do #set "DT_STAMP=%%I" & call set "DT_STAMP=%%DT_STAMP:~0,4%%-%%DT_STAMP:~4,2%%-%%DT_STAMP:~6,2%%_%%DT_STAMP:~8,2%%.%%DT_STAMP:~10,2%%.%%DT_STAMP:~12,2%%"
It uses WMIC to get current local date/time region independent and once again CALL and SET to reformat the date/time string never containing a space to wanted format.
See my answer on Why does %date% produce a different result in batch file executed as scheduled task? for an explanation on how WMIC output is processed by this command line.
By the way: . is used usually as separator between file name and file extension. For that reason it would be better to use also - instead of . between hour and minute and between minute and second.
One more note: The command after call can be also any other command which uses the date/time string directly for example in a file/folder name/path.
Yes you can - with delayed expansion:
setlocal enableDelayedExpansion&set "DS=%date%"&& set "TS=%time: =0%"&set "DT_STAMP=!DS:~10,4!-!DS:~4,2!-!DS:~7,2!_!TS:~0,2!.!TS:~3,2!.!TS:~6,2!"
But this a bad way to format the date time as it depends on localization settings.Why you want to do this on one line? For settings independent approach check this.
It appears that you want an ISO-8601-like formatted date. This will produce a correctly formatted date regardless of the regional/culture settings of the system. If this is used inside a .bat script file, double the % characters on the d variable.
FOR /F %d IN ('powershell -NoLogo -NoProfile -Command Get-Date -UFormat %Y-%m-%d_%H.%M.%S') DO (SET "DT_STAMP=%d")
Or, directly in PowerShell:
$DT_STAMP = Get-Date -UFormat %Y-%m-%d_%H.%M.%S
I run a command script that saves date to text file.
echo %date% > date.txt
Only problem this command saves the day in text file like so
Sun 13/08/2017
When it starts the service, I have a command to change date back
date < date.txt
I get an error
The system cannot accept the date entered.
It needs to show
13/08/2017
For this command to work
date < date.txt
I have someone gave me this command
for /F "tokens=2" %i in ('date /t') do echo %i > date.txt
it removes the day, it runs by itself.
but to run with a script it closes after it executes,
it doesnt seem to run with script.
I have other computers , I use this script and after windows update
It fixes issue; the windows update on other computer removes the day.
This computer had all windows update , but the day still displays
When you type <date> in cmd
The simple solution is using string substitution and write into the text file only the last 10 characters of the region dependent date string of built-in environment variable DATE by using this code:
>date.txt echo %DATE:~-10%
Avoid a space character before redirection operator > on writing a text with echo into a file as this space character is written as trailing space also into the file.
Sometimes it is unsafe to use echo %VariableText%>OutputFile.txt because of the variable text could end with a number in range 1 to 9 which would result in execution of the command line with 1> to 9> which means redirect handle 1 to 9 to the file instead of writing the number 1 to 9 to the file. In such cases it is advisable to specify the redirection to file at beginning of the command line before command echo as done on the command line above.
It would be also possible to use this code to save the date in format DD/MM/YYYY into the ANSI encoded text file date.txt.
#echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /Value') do set "LocalDateTime=%%I"
>date.txt echo %LocalDateTime:~6,2%/%LocalDateTime:~4,2%/%LocalDateTime:~0,4%
This code has the advantage of being independent on which region is set for the current user because the date and time string output by WMIC has always the same format. Run in a command prompt window wmic OS GET LocalDateTime /Value to see the UTF-16 encoded output of WMIC processed by command FOR line be line. The disadvantage is that this code is slower.
On setting the date back with using command DATE the region dependent date format must be known.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
set /?
wmic /?
wmic os /?
wmic os get /?
wmic os get localdatetime /?
Read also the Microsoft article about Using Command Redirection Operators.
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.
Specifically, the 1st for loop example is taken from this answer (which is related to this) and the 2nd for loop example is taken from this answer.
Modified code for both examples copied below:
1st for loop
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%"
2nd for loop
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 how to write the 2nd loop like the 1st loop; i.e. without the use of DELAYEDEXPANSION.
I explain in detail what aschipfl wrote already absolutely right in his comment.
Both batch files work also on Windows 2000 and Windows XP using also cmd.exe as command processor. 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 with enabled command extensions 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 "%~1" or "%~nx1".
The first batch file executes in FOR loop only one command exactly once:
set "dt=%%a"
That command line requires already enabled command extensions. All other commands below are executed after the FOR loop finished. In other words the FOR loop in first batch file does not use a command block to run multiple commands within the FOR loop.
Whenever the Windows command processor 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 FOR is executed and then the commands in the command block are executed with the values of the variables as defined above FOR 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 them by the Windows command processor.
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 CALL is used to process the rest of the line a second time to run the ECHO and the SET commands with environment variable references replaced by their corresponding values without or with string substitution.
The disadvantage of this solution is that CALL is designed primary for calling a batch file from within a batch file. For that reason the command lines above result in searching first in current directory and next in all directories of environment variable PATH for a file with name echo respectively set with a file extension of environment variable PATHEXT. That file searching behavior causes lots of file system accesses, especially on running those command lines in a FOR loop. If there is really found an executable or script file with file name echo or set, the executable respectively the script interpreter of the script file would be executed instead of the internal command of cmd.exe as usually done on using such a command line. So this solution is inefficient and not fail-safe on execution of the batch file.
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
exit /B
: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.
The command line with exit /B avoids a fall through to the code of the subroutine.
The command line with 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
exit /B
: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 FOR loop is exited with using command GOTO to continue execution on a label below. For the meaning of operator & see single line with multiple commands using Windows batch file.
This solution is better than all other methods because the FOR loop executes the single command line with the three commands IF, SET and GOTO only once 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 of the directory does not exist at all.
Of course it would be possible to add a GOTO command also on the other solutions to exit FOR 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.
I'm over my head with this - spent too much time searching already - evidently I don't understand the basics of CMD variables etc. - and it always gives me such a headache
why wouldn't this work?
for %a in (*) do ( set tmpx=%a & echo %tmpx% )
the above code outputs the value of %tmpx% in some other scope - and it is always constant
yes, i run setlocal ENABLEDELAYEDEXPANSION
basically i need to do a simple rename of all files in folder from constantstring_somenameXX.tif to somenameXX.tif, where i.e. constantstring=0000000005
i had to use set because other posts rightly suggested that %a in a for loop has a special behaviour, and the substitutions wouldn't work for it as it is.
i would prefer not to use scripts and/or powershell - unless not using them is impossible
thank you
for %a in (*) do ( set tmpx=%a & echo %tmpx% )
The problem with the previous code is delayed expansion. Yes, you enabled it, but you have not used it, and depending on how you enabled it, it will not work
In cmd, when a line or block of lines (code inside parenthesis) is reached, it is first parsed and then executed. During the parse phase, variable read operations are removed from the command, replaced with the value in the variable before the command starts to execute. So, if you change the value of a variable inside a line/block you can not retrieve the changed value inside the same line/block as there are no variable reads (they were replaced)
setlocal enabledelayedexpansion allows to replace (where needed) the variable read syntax from %var% to !var!, indicating to the parser that the read operation will be delayed until the execution phase.
So, in your case, your code should have been something like
setlocal enabledelayedexpansion & for %a in (*) do ( set "tmpx=%a" & echo !tmpx! )
BUT this will not work (in default configured environments).
cmd has two execution modes: batch file and command line. In your case, you are using command line (no escaped percent sign in for loop) and in command line mode the setlocal enabledelayedexpansion will not work. It is intended for batch files (see setlocal /?)
How to make it work from the command line? By default cmd is started with delayed expansion disabled and you can not enable it if not inside a batch file. But you can start cmd with delayed expansion enabled and run your command in this started instance (see cmd /?)
cmd /v:on /c "for %a in (*) do ( set "tmpx=%a" & echo !tmpx! )"
Anyway, to solve your rename problem, delayed expansion is not needed
for %a in (*_*.tif) do for /f "tokens=1,* delims=_" %b in ("%~nxa") do echo ren "%a" "%c"
That is, for each tif file with an underscore, take the name and extension of the file (%~nxa) as a string, and using the underscore as a delimiter between tokens, retrieve the first token (the text on the left of the first underscore) in %b and the rest of the text (to the right of the underscore) into %c. Now, just rename the original file name (stored in %a) to the contents of %c (the text on the right of the underscore)
In this code rename operations are only echoed to console. If the output is correct, remove the echo command.
! is the character to use rather than % when wanting execution time value. % does when it's read value.
CMD was written by IBM engineers and they were trying to make MSDos a programming language while making sure Dos commands ran the same. So we get a hodge podge.
& seperates commands on a line.
&& executes this command only if previous command's errorlevel is 0.
|| (not used above) executes this command only if previous command's errorlevel is NOT 0
> output to a file
>> append output to a file
< input from a file
| output of one command into the input of another command
^ escapes any of the above, including itself, if needed to be passed to a program
" parameters with spaces must be enclosed in quotes
+ used with copy to concatinate files. E.G. copy file1+file2 newfile
, used with copy to indicate missing parameters. This updates the files modified date. E.G. copy /b file1,,
%variablename% a inbuilt or user set environmental variable
!variablename! a user set environmental variable expanded at execution time, turned with SelLocal EnableDelayedExpansion command
%<number> (%1) the nth command line parameter passed to a batch file. %0 is the batchfile's name.
%* (%*) the entire command line.
%<a letter> or %%<a letter> (%A or %%A) the variable in a for loop. Single % sign at command prompt and double % sign in a batch file.