380

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

1
  • That's why ms windows is the best option as server for applications <3 Commented Feb 6, 2024 at 15:26

13 Answers 13

532

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%
Sign up to request clarification or add additional context in comments.

13 Comments

This is a great trick, I wonder why it doesn't work with a pipe
This only works for output which is a single line of text (subsequent lines omitted after the first line break).
@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"
Do not work for line with spaces. For example: for /f %%i in ('ver') do set VAR=%%i. As wrote @Renat, should add "tokens=*"
@GroovyCakes Your question about multiple lines in the output are answered by this answer on a duplicate question
|
94

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

5 Comments

Two important points: Use tokens to capture and caret to escape the pipe.
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.
Tokens was needed to handle spaces in the output.
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.
using carets for escaping characters reminded me of this answer, which comes into play for more complex commands within the main set of parentheses: for /f "tokens=*" %%i in ('powershell -command (Get-ItemProperty 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Notepad++' -Name '(Default^)'^).'(Default^)'') do set test=%%i
25

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)

1 Comment

do was unexpected at this time.
11

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 multiline variable has a total character limit of 8191, including line feeds.

The multi-line variable (here, allDriver) will only be created if delayed expansion is enabled. This is because it is very difficult to create it in DisabledDelayedExpansion mode, and it is useless in this mode as multi-line variables can only be handled in EnabledDelayedExpansion mode.

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

Comments

10

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

Comments

4

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

application arg0 arg1
set VAR=%errorlevel%

3 Comments

Unfortunately, the output is a string.
ok. i will keep this for posterity, but take a look at @jdigital's link, which talks about piping output to a temp file.
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.
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

Comments

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

Comments

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

Comments

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

Comments

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

Comments

0

Though is far too late for an anwser, but I'd like to add this as a supplement (might be easy one).

@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
call :find_LineNumber data.txt LN
echo "Found first occurrence @!LN! in data.txt"

:find_LineNumber 
for /f "delims=:" %%n in ('findstr/n /c:"The target line" "%~1"')do(set.%~2=%%n&cmd>&0 2>NUL)
EXIT /B

Comments

-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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.