361

I need to assign the output of a program to a variable using a MS batch file.

So in GNU Bash shell I would use VAR=$(application arg0 arg1). I need a similar behavior in Windows using a batch file.

Something like set VAR=application arg0 arg1.

Similar Questions

KyleMit
  • 30,350
  • 66
  • 462
  • 664
initialZero
  • 6,197
  • 9
  • 29
  • 38

12 Answers12

516

One way is:

application arg0 arg1 > temp.txt
set /p VAR=<temp.txt

Another is:

for /f %%i in ('application arg0 arg1') do set VAR=%%i

Note that the first % in %%i is used to escape the % after it and is needed when using the above code in a batch file rather than on the command line. Imagine, your test.bat has something like:

for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%
Wolf
  • 9,679
  • 7
  • 62
  • 108
Carlos Gutiérrez
  • 13,972
  • 5
  • 37
  • 47
  • 14
    This is a great trick, I wonder why it doesn't work with a pipe – Bill K Apr 10 '13 at 22:26
  • 29
    This only works for output which is a single line of text (subsequent lines omitted after the first line break). – GroovyCakes Aug 07 '15 at 21:46
  • 25
    @Machta the pipe must be escaped with a ^ sign before of it, inside the expression in parens. Example: `for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"` – yodabar Aug 19 '15 at 22:54
  • 13
    Do not work for line with spaces. For example: for /f %%i in ('ver') do set VAR=%%i. As wrote @Renat, should add "tokens=*" – Yura Shinkarev Jan 13 '16 at 13:02
  • I would also add that the [`FOR` command options](http://ss64.com/nt/for_cmd.html) (i.e. `usebackq` and `delims`) can help a lot with complex/long commands, for instance [MediaInfo](http://superuser.com/questions/597626/windows-get-duration-of-video-file-from-command-line#comment735613_597634): `for /F "usebackq delims=^" %%i in (\`"C:\progra~2\path\mediainfo.exe --Output=General;%%Duration/String3%% %1"\`) do set getter=%%i` – WoodrowShigeru Jul 03 '16 at 12:35
  • 2
    @GroovyCakes Your question about multiple lines in the output are answered by [this answer](https://stackoverflow.com/a/6362922/327074) on a duplicate question – icc97 May 31 '17 at 16:09
  • What if I want to issue command which has % in it e.g.: for /f %%i in ('git log -1 --pretty=format:"%%H"') do set GIT_COMMIT=%%i – Wakan Tanka Jan 25 '19 at 11:44
  • Is the second method faster? – Prajwal Aug 23 '19 at 07:52
  • When I try this I am told "incorrect syntax near %%i" .. copy & pasta – HelloWorld Sep 05 '22 at 17:29
  • @HelloWorld Use `%%i` in a bat file, `%i` if testing directly in the command line – Carlos Gutiérrez Sep 06 '22 at 19:26
  • @CarlosGutiérrez Thanks but I tried both in bat file and it doesn't work :( I'm using a git pre-commit hook though and I heard git has it's own port or something? Might be subtly different from a windows batch file in some way? – HelloWorld Sep 07 '22 at 09:00
  • How do you get `IN`'s command to support spaces? e.g. `IN ( '"My Executable.exe" "Argument #1" Argument #2"')`? The former would fail just putting `"My` into the set variable. – Matt Arnold Dec 14 '22 at 15:51
87

As an addition to this previous answer, pipes can be used inside a for statement, escaped by a caret symbol:

    for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i
Community
  • 1
  • 1
Renat
  • 7,718
  • 2
  • 20
  • 34
  • 2
    Two important points: Use tokens to capture and caret to escape the pipe. – Christopher Oezbek Oct 29 '14 at 12:13
  • 7
    Equivalent version that works on the CLI and can be copy-pasted for easier tinkering: `for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %i` But in general, the `usebackq` should be used to handle complex commands. – Amit Naidu Dec 14 '17 at 16:33
  • 2
    Tokens was needed to handle spaces in the output. – Mark Ingram May 23 '18 at 11:41
  • Quotes work as well for me, like this: `for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i`. Easier for me if there're no quotes in the command itself. – Paul Apr 22 '20 at 23:31
20

When executing the following in the command line:

for /f %%i in ('application arg0 arg1') do set VAR=%%i

I was getting the error:

%%i was unexpected at this time.

To fix, I changed to use a single % sign like this:

for /f %i in ('application arg0 arg1') do set VAR=%i

Summary:

  • Use %% when in a batch file
  • Use % when outside a batch file (on a command line)
Nuno André
  • 4,739
  • 1
  • 33
  • 46
Munish Mehta
  • 353
  • 3
  • 9
10

@OP, you can use for loops to capture the return status of your program, if it outputs something other than numbers

ghostdog74
  • 327,991
  • 56
  • 259
  • 343
10

You could use a batch macro for simple capturing of command outputs, a bit like the behavior of the bash shell.

The usage of the macro is simple and looks like:

%$set% VAR=application arg1 arg2

it also works even with pipes:

%$set% allDrives="wmic logicaldisk get name /value | findstr "Name""

The macro uses the variable like an array and stores each line in a separate index.
In the sample of %$set% allDrives="wmic logicaldisk" there will the following variables created:

allDrives.Len=5
allDrives.Max=4
allDrives[0]=Name=C:
allDrives[1]=Name=D:
allDrives[2]=Name=F:
allDrives[3]=Name=G:
allDrives[4]=Name=Z:
allDrives=<contains the complete text with line feeds>

To use it, it's not important to understand how the macro itself works.

The full example:

@echo off
setlocal

call :initMacro

%$set% ipOutput="ipconfig"
call :ShowVariable ipOutput
echo First line is %ipOutput[0]%

echo( 
%$set% driveNames="wmic logicaldisk get name /value | findstr "Name""
call :ShowVariable driveNames

exit /b

:ShowVariable
setlocal EnableDelayedExpansion
for /L %%n in (0 1 !%~1.max!) do (
    echo %%n: !%~1[%%n]!
)
echo(
exit /b

:initMacro
if "!!"=="" (
    echo ERROR: Delayed Expansion must be disabled while defining macros
    (goto) 2>nul
    (goto) 2>nul
)
(set LF=^
%=empty=%
)
(set \n=^^^
%=empty=%
)

set $set=FOR /L %%N in (1 1 2) dO IF %%N==2 ( %\n%
    setlocal EnableDelayedExpansion                                 %\n%
    for /f "tokens=1,* delims== " %%1 in ("!argv!") do (            %\n%
        endlocal                                                    %\n%
        endlocal                                                    %\n%
        set "%%~1.Len=0"                                            %\n%
        set "%%~1="                                                 %\n%
        if "!!"=="" (                                               %\n%
            %= Used if delayed expansion is enabled =%              %\n%
                setlocal DisableDelayedExpansion                    %\n%
                for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                if "!!" NEQ "" (                                    %\n%
                    endlocal                                        %\n%
                    )                                               %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set pathExt=:                                       %\n%
                set path=;                                          %\n%
                set "line=!line:^=^^!"                              %\n%
                set "line=!line:"=q"^""!"                           %\n%
                call set "line=%%line:^!=q""^!%%"                   %\n%
                set "line=!line:q""=^!"                             %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") do (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") Do (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L" !                      %\n%
                        if %%C == 0 (                               %\n%
                            set "%%~1=%%~L" !                       %\n%
                        ) ELSE (                                    %\n%
                            set "%%~1=!%%~1!!LF!%%~L" !             %\n%
                        )                                           %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        ) ELSE (                                                    %\n%
            %= Used if delayed expansion is disabled =%             %\n%
            for /F "delims=" %%O in ('"%%~2 | findstr /N ^^"') do ( %\n%
                setlocal DisableDelayedExpansion                    %\n%
                set "line=%%O"                                      %\n%
                setlocal EnableDelayedExpansion                     %\n%
                set "line="!line:*:=!""                             %\n%
                for /F %%C in ("!%%~1.Len!") DO (                   %\n%
                    FOR /F "delims=" %%L in ("!line!") DO (         %\n%
                        endlocal                                    %\n%
                        endlocal                                    %\n%
                        set "%%~1[%%C]=%%~L"                        %\n%
                    )                                               %\n%
                    set /a %%~1.Len+=1                              %\n%
                )                                                   %\n%
            )                                                       %\n%
        )                                                           %\n%
        set /a %%~1.Max=%%~1.Len-1                                  %\n%
)                                                                   %\n%
    ) else setlocal DisableDelayedExpansion^&set argv=

goto :eof
Community
  • 1
  • 1
jeb
  • 78,592
  • 17
  • 171
  • 225
6

assuming that your application's output is a numeric return code, you can do the following

application arg0 arg1
set VAR=%errorlevel%
akf
  • 38,619
  • 8
  • 86
  • 96
  • 5
    Unfortunately, the output is a string. – initialZero Feb 24 '10 at 03:08
  • ok. i will keep this for posterity, but take a look at @jdigital's link, which talks about piping output to a temp file. – akf Feb 24 '10 at 03:19
  • 1
    The program's output to stdout and stderr is different from it's integer return value. A program can both return an integer value like in the example above, while also sending a string to the console (or redirected to a file or elsewhere). They are not mutually exclusive and are two different concepts. – David Rector Nov 17 '16 at 19:45
3

In addition to the answer, you can't directly use output redirection operators in the set part of for loop (e.g. if you wanna hide stderror output from a user and provide a nicer error message). Instead, you have to escape them with a caret character (^):

for /f %%O in ('some-erroring-command 2^> nul') do (echo %%O)

Reference: Redirect output of command in for loop of batch script

Community
  • 1
  • 1
Kubo2
  • 331
  • 3
  • 16
2
@echo off
SETLOCAL ENABLEDELAYEDEXPANSION

REM Prefer backtick usage for command output reading:
REM ENABLEDELAYEDEXPANSION is required for actualized
REM  outer variables within for's scope;
REM within for's scope, access to modified 
REM outer variable is done via !...! syntax.

SET CHP=C:\Windows\System32\chcp.com

FOR /F "usebackq tokens=1,2,3" %%i IN (`%CHP%`) DO (
    IF "%%i" == "Aktive" IF "%%j" == "Codepage:" (
        SET SELCP=%%k
        SET SELCP=!SELCP:~0,-1!
    )
)
echo actual codepage [%SELCP%]

ENDLOCAL
Kurt Van den Branden
  • 11,995
  • 10
  • 76
  • 85
rcm
  • 21
  • 3
1

I wrote the script that pings google.com every 5 seconds and logging results with current time. Here you can find output to variables "commandLineStr" (with indices)

@echo off

:LOOPSTART

echo %DATE:~0% %TIME:~0,8% >> Pingtest.log

SETLOCAL ENABLEDELAYEDEXPANSION
SET scriptCount=1
FOR /F "tokens=* USEBACKQ" %%F IN (`ping google.com -n 1`) DO (
  SET commandLineStr!scriptCount!=%%F
  SET /a scriptCount=!scriptCount!+1
)
@ECHO %commandLineStr1% >> PingTest.log
@ECHO %commandLineStr2% >> PingTest.log
ENDLOCAL

timeout 5 > nul

GOTO LOOPSTART
Ja Vy
  • 11
  • 1
1

Some macros to set the output of a command to a variable/

For directly in the command prompt

c:\>doskey assign=for /f "tokens=1,2 delims=," %a in ("$*") do @for /f "tokens=* delims=" %# in ('"%a"') do @set "%b=%#"

c:\>assign WHOAMI /LOGONID,my-id

c:\>echo %my-id%

Macro with arguments

As this macro accepts arguments as a function i think it is the neatest macro to be used in a batch file:

@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%

FOR /F macro

not so easy to read as the previous 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%

Macro using a temp file

Easier to read , it is not so slow if you have a SSD drive but still it creates a temp file.

@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%##
npocmaka
  • 55,367
  • 18
  • 148
  • 187
0

This answer may help as well : https://stackoverflow.com/a/61666083/2444948

But it is actually writing a file to read it ... The code is not from me:

(cmd & echo.) >2 & (set /p =)<2

REM Example :
(echo foo & echo.) >2 & (set /p bar=)<2
Dorian Grv
  • 421
  • 5
  • 9
-1

//set str=%myVar:*:=%// this replace all before ":" to " "                                                         //findstr "Subnet Mask" my_log.txt > my_find.txt// search "string" in file and save in new file //">" remake file, if use ">>" add in old file// im recommend use ">"

@echo off
 
ipconfig > my_log.txt
findstr "Subnet Mask" my_log.txt > my_find.txt 
set /p myVar= < my_find.txt 
echo %myVar%

set str=%myVar:*:=%
set str=%str:.= im_dot %
echo %str%

pause
Cody toys
  • 11
  • 1