Set the value of a variable with the result of a command in a Windows batch file

When working in a Bash environment, to set the value of a variable as the result of a command, I usually do:

var=$(command -args)

where var is the variable set by the command command -args. I can then access that variable as $var.

A more conventional way to do this which is compatible with almost every Unix shell is:

set var=`command -args`

That said, how can I set the value of a variable with the result of a command in a Windows batch file? I've tried:

set var=command -args

But I find that var is set to command -args rather than the output of the command.


Solution 1:

To do what Jesse describes, from a Windows batch file you will need to write:

for /f "delims=" %%a in ('ver') do @set foobar=%%a 

But, I instead suggest using Cygwin on your Windows system if you are used to Unix-type scripting.

Solution 2:

One needs to be somewhat careful, since the Windows batch command:

for /f "delims=" %%a in ('command') do @set theValue=%%a

does not have the same semantics as the Unix shell statement:

theValue=`command`

Consider the case where the command fails, causing an error.

In the Unix shell version, the assignment to "theValue" still occurs, any previous value being replaced with an empty value.

In the Windows batch version, it's the "for" command which handles the error, and the "do" clause is never reached -- so any previous value of "theValue" will be retained.

To get more Unix-like semantics in Windows batch script, you must ensure that assignment takes place:

set theValue=
for /f "delims=" %%a in ('command') do @set theValue=%%a

Failing to clear the variable's value when converting a Unix script to Windows batch can be a cause of subtle errors.

Solution 3:

Here's how I do it when I need a database query's results in my batch file:

sqlplus -S schema/schema@db @query.sql> __query.tmp
set /p result=<__query.tmp
del __query.tmp

The key is in line 2: "set /p" sets the value of "result" to the value of the first line (only) in "__query.tmp" via the "<" redirection operator.

Solution 4:

The only way I've seen it done is if you do this:

for /f "delims=" %a in ('ver') do @set foobar=%a

ver is the version command for Windows and on my system it produces:

Microsoft Windows [Version 6.0.6001]

Source

Solution 5:

Here are two approaches:

@echo off

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;;set "[[=>"#" 2>&1&set/p "&set "]]==<# & del /q # >nul 2>&1" &::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:: --examples

::assigning chcp command output to %code-page% variable
chcp %[[%code-page%]]%
echo 1: %code-page%

::assigning whoami command output to %its-me% variable
whoami %[[%its-me%]]%
echo 2: %its-me%


::::::::::::::::::::::::::::::::::::::::::::::::::
;;set "{{=for /f "tokens=* delims=" %%# in ('" &::
;;set "--=') do @set ""                        &::
;;set "}}==%%#""                               &::
::::::::::::::::::::::::::::::::::::::::::::::::::

:: --examples

::assigning ver output to %win-ver% variable
%{{% ver %--%win-ver%}}%
echo 3: %win-ver%


::assigning hostname output to %my-host% variable
%{{% hostname %--%my-host%}}%
echo 4: %my-host%

the output of the script:

1: Active code page: 65001
2: mypc\user
3: Microsoft Windows [Version 10.0.19042.1110]
4: mypc

Explanation:

1] the parts ending with &:: are end-of-line comment and can be ignored. I've put them only for macro enclosing

2] ;; at the start of the line will be ignored as ; is a standard delimiter for batch script. It is put there as it reminds a comment and to further enhance where the macro definitions are assigned.

3] the technique used is called 'macro' it assigns command to a variable and when the variable is invoked the command is executed.

4] the first macro defined contains two parts:

set "[[=>"#" 2>&1&set/p "

and

set "]]==<# & del /q # >nul 2>&1"

separated by & which allows me to define them on one line. The first takes the output of a command and redirects it ot a file #. And adds set/p in order to start the reading the file with set /p technique .The second macro finishes the set /p reading with <# and then deletes the file. The text between two macros is the name of the variable. Something like set /p myVariable=<#

5] The second macro contains three parts and expanded is just a for /f loop. Probably can be done in a more elegant way.