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
.
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
.
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%
for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"
–
Touber 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=%%i
–
Templet %%i
in a bat file, %i
if testing directly in the command line –
Anthia 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 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
for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %i
But in general, the usebackq
should be used to handle complex commands. –
Drive 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 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:
%%
when in a batch file%
when outside a batch file (on a command line)@OP, you can use for loops to capture the return status of your program, if it outputs something other than numbers
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
assuming that your application's output is a numeric return code, you can do the following
application arg0 arg1
set VAR=%errorlevel%
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
@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
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
Some macros to set the output of a command to a variable/
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%
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%
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%
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%##
//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
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
© 2022 - 2024 — McMap. All rights reserved.