374

Is it possible to set a statement's output of a batch file to a variable, for example:

findstr testing > %VARIABLE%

echo %VARIABLE%
g t
  • 7,287
  • 7
  • 50
  • 85
Dennis
  • 3,867
  • 5
  • 17
  • 7
  • Actually the original seems to be [How do I get the result of a command in a variable in windows?](http://stackoverflow.com/q/108439/12892). – Cristian Ciupitu Jul 01 '14 at 16:53
  • None of the answers seems to work for me. My command is "openssl dgst -sha384 -binary %1% | openssl base64 -A" and I wish the string output to be stored in a variable in a batch/command file. – David Spector Apr 05 '21 at 17:00
  • Somewhat inefficient solution: @echo off openssl dgst -sha384 -binary %1% | openssl base64 -A > tmp set /p a= < tmp del tmp echo %a% – David Spector Apr 05 '21 at 17:07
  • Write a python script that does the job? – Josja Mar 03 '23 at 10:30

9 Answers9

391
FOR /F "tokens=* USEBACKQ" %%F IN (`command`) DO (
SET var=%%F
)
ECHO %var%

I always use the USEBACKQ so that if you have a string to insert or a long file name, you can use your double quotes without screwing up the command.

Now if your output will contain multiple lines, you can do this

SETLOCAL ENABLEDELAYEDEXPANSION
SET count=1
FOR /F "tokens=* USEBACKQ" %%F IN (`command`) DO (
  SET var!count!=%%F
  SET /a count=!count!+1
)
ECHO %var1%
ECHO %var2%
ECHO %var3%
ENDLOCAL
Anthony Miller
  • 15,101
  • 28
  • 69
  • 98
  • 6
    Worked for me in Win7 system, thanks! (and yes, it's 7 years of usefullness) P.S. Don't forget to expand % to %% in commands! – Dmitry Ilukhin Jan 16 '18 at 18:09
  • 1
    This works great... unless the output contains exclamation points (!), as these will be interpreted as control characters when using `ENABLEDELAYEDEXPANSION` – JonathanDavidArndt Mar 25 '18 at 19:19
  • 1
    It does work well, except if you need to use `|` in which case it doesn't work. – Matt Vukomanovic Jun 15 '18 at 07:45
  • 16
    @MattVukomanovic it works for me using `^|` in place of `|`, as described [here](https://stackoverflow.com/a/108511/5170004) – AST Jun 21 '18 at 13:34
  • 1
    Is it possible to capture the exit code of `command` anyhow, please? I'm sure it's returning a non-zero code but `%ERRORLEVEL%` always contains 0, no matter where I try to use it (even inside the `do` block). So I guess some part of that `for` construct is overwriting it. BTW It's unbelievable how crazy looking code is needed for something so elementary. – David Ferenczy Rogožan Nov 29 '18 at 21:08
  • If the command is simple (without space), you can do `set var=%command%` – Sandburg Feb 22 '19 at 08:35
  • backticks or simplequotes ? – Sandburg Oct 09 '19 at 11:18
  • @DawidFerenczyRogožan i know this is 2 years too late but just coming back to the platform LOL. I believe you'd have to capture the %ERRORLEVEL% in the first line of the do-loop and then export the output (to a file or variable). – Anthony Miller Jan 28 '20 at 23:16
  • 4
    This bit is REALLY clever: `SET var!count!=%%F` I've not seen dynamic variable names in a batch file before. – GregHNZ Mar 09 '21 at 20:30
  • @DavidFerenczyRogožan: Yes, you can. See example I've posted; it voids the need for a `for` loop to capture value of a command and store in a variable. – Zimba Aug 26 '21 at 19:28
  • @DavidFerenczyRogožan Have you tried `!ERRORLEVEL!` within the loop? – Martin Braun Jan 22 '22 at 06:35
  • Note that double percent is for scripts and single percent is for command line. I got surprised by this. – jcxz Jan 20 '23 at 11:51
  • Trying to use this to capture the output of an `ffprobe` command and it breaks... – AutoBaker Feb 10 '23 at 15:12
  • @AutoBaker: no, it does not brake, and when it does, please create a new question with your problem. (do not forget to add a link to this answer) – Luuk Jul 15 '23 at 08:05
116

In a single line:

FOR /F "tokens=*" %%g IN ('your command') do (SET VAR=%%g)

The command output will be set in %g then in VAR.

More information here: https://ss64.com/nt/for_cmd.html

Massimo
  • 3,171
  • 3
  • 28
  • 41
Yuri
  • 1,691
  • 2
  • 13
  • 12
105

I found this thread on that there Interweb thing. Boils down to:

@echo off 
setlocal enableextensions 
for /f "tokens=*" %%a in ( 
'VER' 
) do ( 
set myvar=%%a 
) 
echo/%%myvar%%=%myvar% 
pause 
endlocal 

You can also redirect the output of a command to a temporary file, and then put the contents of that temporary file into your variable, likesuchashereby. It doesn't work with multiline input though.

cmd > tmpFile 
set /p myvar= < tmpFile 
del tmpFile 

Credit to the thread on Tom's Hardware.

Roelant
  • 4,508
  • 1
  • 32
  • 62
dolphy
  • 6,218
  • 4
  • 24
  • 32
  • 8
    Only drawback to bottom approach (which is preferable in all other ways) is that it doesn't work with multi-line output. – dgo Nov 29 '16 at 15:46
  • For VER I would go another way: for /f "tokens=2 delims=[,]" %%a in ('ver') do set version %%a echo %version% – Hardoman Apr 06 '17 at 14:44
  • 2
    you are the second result for likesuchashereby - https://imagebin.ca/v/4NPSlQFgifce – Shmuel Kamensky Nov 21 '18 at 21:03
  • 2
    Your second example helped me greatly in writing a batch file to check the version of chromedriver.exe versus a text file containing a version number. I'm an old DOS dinosaur, and was not aware of the switches to the set command. The other stuff was overkill for me. – Bill Hileman Feb 11 '19 at 16:11
37

If you don't want to output to a temp file and then read into a variable, this code stores result of command direct into a variable:

FOR /F %i IN ('findstr testing') DO set VARIABLE=%i
echo %VARIABLE%

If you want to enclose search string in double quotes:

FOR /F %i IN ('findstr "testing"') DO set VARIABLE=%i

If you want to store this code in a batch file, add an extra % symbol:

FOR /F %%i IN ('findstr "testing"') DO set VARIABLE=%%i

A useful example to count the number of files in a directory & store in a variable: (illustrates piping)

FOR /F %i IN ('dir /b /a-d "%cd%" ^| find /v /c "?"') DO set /a count=%i

Note the use of single quotes instead of double quotes " or grave accent ` in the command brackets. This is cleaner alternative to delims, tokens or usebackq in for loop.

Update 27/8/2021:

Another method is to set errorlevel variable, although many would discourage setting errorlevel on large scripts or when new to cmd flavor of the installed OS variant.

This method works where (return) value to be stored fits in a 32-bit integer.

eg. to count the number of files in a directory & store in a variable called count:

(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& cmd /c exit /b %myVar%)
set count=%errorlevel%

Verbose - Win CMD integer limits tests:

Win CMD arithmetic limit: 2147483647 (32-bit integers)
Stack overflow would continue count at -2147483648 and reset again after reaching 2147483647

REM See tests below:
cmd /c exit /b 2147483647
echo %errorlevel%
2147483647

cmd /c exit /b 2147483648
echo %errorlevel%
-2147483648

cmd /c exit /b 2147483649
echo %errorlevel%
-2147483647

Above method can be modified to return encoded strings to be decoded in parent process (within 32 bit limitation).

A 3rd illustration, although of limited use (because the variable is set in child process, not parent) is:

(dir /b /a-d ^| find /v /c "?") | (set /p myVar=& set myVar)

In this case the value of myVar is set to the number of files in the directory

Tested on Win 10 CMD.

Zimba
  • 2,854
  • 18
  • 26
30

To read a file...

set /P Variable=<File.txt

To Write a file

@echo %DataToWrite%>File.txt

note; having spaces before the <> character causes a space to be added at the end of the variable, also

To add to a file,like a logger program, First make a file with a single enter key in it called e.txt

set /P Data=<log0.log
set /P Ekey=<e.txt
@echo %Data%%Ekey%%NewData%>log0.txt

your log will look like this

Entry1
Entry2 

and so on

Anyways a couple useful things

28

These answers were all so close to the answer that I needed. This is an attempt to expand on them.

In a Batch file

If you're running from within a .bat file and you want a single line that allows you to export a complicated command like jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json to a variable named AWS_ACCESS_KEY then you want this:

FOR /F "tokens=* USEBACKQ" %%g IN (`jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json`) do (SET "AWS_ACCESS_KEY=%%g")

On the Command Line

If you're at the C:\ prompt you want a single line that allows you to run a complicated command like jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json to a variable named AWS_ACCESS_KEY then you want this:

FOR /F "tokens=* USEBACKQ" %g IN (`jq -r ".Credentials.AccessKeyId" c:\temp\mfa-getCreds.json`) do (SET "AWS_ACCESS_KEY=%g")

Explanation

The only difference between the two answers above is that on the command line, you use a single % in your variable. In a batch file, you have to double up on the percentage signs (%%).

Since the command includes colons, quotes, and parentheses, you need to include the USEBACKQ line in the options so that you can use backquotes to specify the command to run and then all kinds of funny characters inside of it.

Ryan Shillington
  • 23,006
  • 14
  • 93
  • 108
  • 1
    Well, apparently someone is having the exact same problem I'm facing of the wonders of piping JSON from the AWS cli using batch scripts hah – Trinidad Oct 13 '20 at 22:17
17

Some notes and some tricks.

The 'official' way to assign result to a variable is with FOR /F though in the other answers is shown how a temporary file can be used also.

For command processing FOR command has two forms depending if the usebackq option is used. In the all examples below the whole output is used without splitting it.

FOR /f "tokens=* delims=" %%A in ('whoami') do @set "I-Am=%%A"
FOR /f "usebackq tokens=* delims=" %%A in (`whoami`) do @set "I-Am=%%A"

and if used directly in the console:

FOR /f "tokens=* delims=" %A in ('whoami') do set "I-Am=%A"
FOR /f "usebackq tokens=* delims=" %A in (`whoami`) do set "I-Am=%A"

%%A is a temporary variable available only on the FOR command context and is called token.The two forms can be useful in case when you are dealing with arguments containing specific quotes. It is especially useful with REPL interfaces of other languages or WMIC. Though in both cases the expression can be put in double quotes and it still be processed.

Here's an example with python (it is possible to transition the expression in the brackets on a separate line which is used for easier reading):

@echo off

for /f "tokens=* delims=" %%a in (
  '"python -c ""print("""Message from python""")"""'
) do (
    echo processed message from python: "%%a"
)

To use an assigned variable in the same FOR block check also the DELAYED EXPANSION

And some tricks

To save yourself from writing all the arguments for the FOR command you can use MACRO for assigning the result to variable:

@echo off

::::: ---- defining the assign macro ---- ::::::::
setlocal DisableDelayedExpansion
(set LF=^
%=EMPTY=%
)
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"

::set argv=Empty
set assign=for /L %%n in (1 1 2) do ( %\n%
   if %%n==2 (%\n%
      setlocal enableDelayedExpansion%\n%
      for /F "tokens=1,2 delims=," %%A in ("!argv!") do (%\n%
         for /f "tokens=* delims=" %%# in ('%%~A') do endlocal^&set "%%~B=%%#" %\n%
      ) %\n%
   ) %\n%
) ^& set argv=,

::::: -------- ::::::::


:::EXAMPLE
%assign% "WHOAMI /LOGONID",result
echo %result%

the first argument to the macro is the command and the second the name of the variable we want to use and both are separated by , (comma). Though this is suitable only for straight forward scenarios.

If we want a similar macro for the console we can use DOSKEY

doskey assign=for /f "tokens=1,2 delims=," %a in ("$*") do @for /f "tokens=* delims=" %# in ('"%a"') do @set "%b=%#"
rem  -- example --
assign WHOAMI /LOGONID,my-id
echo %my-id%

DOSKEY does accept double quotes as enclosion for arguments so this also is useful for more simple scenarios.

FOR also works well with pipes which can be used for chaining commands (though it is not so good for assigning a variable.

hostname |for /f "tokens=* delims=" %%# in ('more') do @(ping %%#)

Which also can be beautified with macros:

@echo off
:: --- defining chain command macros ---
set "result-as-[arg]:=|for /f "tokens=* delims=" %%# in ('more') do @("
set "[arg]= %%#)"
:::  --------------------------  :::

::Example:
hostname %result-as-[arg]:% ping %[arg]%

And for completnes macros for the temp file approach (no doskey definition ,but it also can be easy done.If you have a SSD this wont be so slow):

@echo off

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

chcp %[[%code-page%]]%
echo ~~%code-page%~~

whoami %[[%its-me%]]%
echo ##%its-me%##

For /f with another macro:

::::::::::::::::::::::::::::::::::::::::::::::::::
;;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%
npocmaka
  • 55,367
  • 18
  • 148
  • 187
2
cd %windir%\system32\inetsrv

@echo off

for /F "tokens=* USEBACKQ" %%x in (      
        `appcmd list apppool /text:name`
       ) do (
            echo|set /p=  "%%x - " /text:name & appcmd.exe list apppool "%%x" /text:processModel.identityType
       )

echo %date% & echo %time%

pause
Dado
  • 1,016
  • 1
  • 12
  • 20
  • 1
    I can't see how this solves the question. `appcmd` isn't a standard program and I can't see where you assign program output to a variable. At last you need some more explanations – jeb Aug 04 '17 at 05:58
2

I most cases, creating a temporary file named after your variable name might be acceptable. (as you are probably using meaningful variables name...)

Here, my variable name is SSH_PAGEANT_AUTH_SOCK

dir /w "\\.\pipe\\"|find "pageant" > %temp%\SSH_PAGEANT_AUTH_SOCK && set /P SSH_PAGEANT_AUTH_SOCK=<%temp%\SSH_PAGEANT_AUTH_SOCK
131
  • 3,071
  • 31
  • 32