Assign output of a program to a variable using a MS batch file
Asked Answered
I

12

369

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

Ivers answered 24/2, 2010 at 2:33 Comment(1)
That's why ms windows is the best option as server for applications <3Unschooled
A
522

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%
Antilogism answered 26/2, 2010 at 7:13 Comment(12)
This is a great trick, I wonder why it doesn't work with a pipeGuizot
This only works for output which is a single line of text (subsequent lines omitted after the first line break).Oxy
@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"Touber
Do not work for line with spaces. For example: for /f %%i in ('ver') do set VAR=%%i. As wrote @Renat, should add "tokens=*"Gunning
I would also add that the FOR command options (i.e. usebackq and delims) can help a lot with complex/long commands, for instance MediaInfo: for /F "usebackq delims=^" %%i in (`"C:\progra~2\path\mediainfo.exe --Output=General;%%Duration/String3%% %1"`) do set getter=%%iTemplet
@Oxy Your question about multiple lines in the output are answered by this answer on a duplicate questionNonaggression
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=%%iDactylography
Is the second method faster?Carlotacarlotta
When I try this I am told "incorrect syntax near %%i" .. copy & pastaLeroi
@Leroi Use %%i in a bat file, %i if testing directly in the command lineAnthia
@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?Leroi
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.Illative
D
90

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
Detroit answered 18/10, 2013 at 7:11 Comment(4)
Two important points: Use tokens to capture and caret to escape the pipe.Beguile
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.Drive
Tokens was needed to handle spaces in the output.Fruiter
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.Rosaniline
S
24

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)
Sidwel answered 7/12, 2016 at 11:14 Comment(1)
do was unexpected at this time.Unschooled
E
10

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

Eutectoid answered 24/2, 2010 at 2:47 Comment(0)
Y
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
Yeomanry answered 29/1, 2019 at 16:14 Comment(0)
K
6

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

application arg0 arg1
set VAR=%errorlevel%
Kellum answered 24/2, 2010 at 2:37 Comment(3)
Unfortunately, the output is a string.Ivers
ok. i will keep this for posterity, but take a look at @jdigital's link, which talks about piping output to a temp file.Kellum
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.Tompkins
R
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

Rainbow answered 15/7, 2015 at 11:46 Comment(0)
G
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
Globuliferous answered 1/9, 2016 at 13:22 Comment(0)
T
2

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
Twohanded answered 2/4, 2018 at 12:25 Comment(0)
M
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%##
Myotonia answered 9/11, 2020 at 11:6 Comment(0)
S
-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
Silveira answered 28/8, 2022 at 17:30 Comment(0)
I
-1

This answer may help as well : https://mcmap.net/q/93496/-set-output-of-a-command-as-a-variable-with-pipes-duplicate

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
Iverson answered 17/11, 2022 at 17:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.