Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can multiple dependent variables be set on the same line in a batch file?

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)
like image 587
JonathanDavidArndt Avatar asked Jan 02 '23 23:01

JonathanDavidArndt


1 Answers

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=,
like image 68
jeb Avatar answered Jan 05 '23 15:01

jeb