How do I get the result of a command in a variable in windows? [duplicate]
Asked Answered
M

13

177

I'm looking to get the result of a command as a variable in a Windows batch script (see how to get the result of a command in bash for the bash scripting equivalent). A solution that will work in a .bat file is preferred, but other common windows scripting solutions are also welcome.

Mcglone answered 20/9, 2008 at 15:13 Comment(3)
John, it's ridiculously hard to find this very useful question. Could you please consider adding alternative phrasing like How to capture the output of a a program into a variable in a Windows batch file?Ulrica
Google displayed this page ranked 3rd.Martyr
@MichaelFreidgeim Fair point, I'd say these questions were an exception though, there's about 4 of them all asked years ago, they have different qualities of answers on each one and none of them are definitive.Lyda
C
44

If you have to capture all the command output you can use a batch like this:

@ECHO OFF
IF NOT "%1"=="" GOTO ADDV
SET VAR=
FOR /F %%I IN ('DIR *.TXT /B /O:D') DO CALL %0 %%I
SET VAR
GOTO END

:ADDV
SET VAR=%VAR%!%1

:END

All output lines are stored in VAR separated with "!".

But if only a single-line console-output is expected, try:

@ECHO off
@SET MY_VAR=
FOR /F %%I IN ('npm prefix') DO @SET "MY_VAR=%%I"

@REM Do something with MY_VAR variable...

@John: is there any practical use for this? I think you should watch PowerShell or any other programming language capable to perform scripting tasks easily (Python, Perl, PHP, Ruby)

Crysta answered 20/9, 2008 at 16:23 Comment(6)
The single line answer will solve the specific case I have. I just figured there was a multi-line option (or an easier single line option). I guess the capabilities of bat files just aren't that great. The need for it is for bat scripts wrapping Java apps. Building classpaths mainly.Mcglone
Be very careful with that. GWT also tried to use batch files for starting Java with specific classpaths, which failed horrible as soon as you're getting to directories with non-ASCII characters (in that case it was my home :)). They since rewrote that with VBS.Celindaceline
is there any practical use for this? Are You kidding? This is used all the time in other shells (all GNU/Linux ones I guess) and it's very useful.Ulrica
@PiotrDobrogost I think what he was trying to say was that bash scripts are a horrible relic of the past (You need to use a for loop just to capture the output of a program? Seriously?), and if you ever get to the point where you find yourself needing to use variables, you should use something more modern like PowerShell.Minutely
There is a practical use, actually... kinda. I want to use a PowerShell script to find a particular Visual Studio path, but the thing I need out of that path is a batch file that sets a bunch of env vars so I can call editbin... So I need to find the path and get it back out to the calling instance of cmd so I can run it there. ...Yes, this is as terrible as sounds. Visual Studio makes me want to cry sometimes. @Minutely I think you meant to say that batch scripts are a horrible relic of the past. ;)Honeysweet
If the command had been simple (without space), you could have done set var=%command%Chump
N
107

The humble for command has accumulated some interesting capabilities over the years:

D:\> FOR /F "delims=" %i IN ('date /t') DO set today=%i
D:\> echo %today%
Sat 20/09/2008

Note that "delims=" overwrites the default space and tab delimiters so that the output of the date command gets gobbled all at once.

To capture multi-line output, it can still essentially be a one-liner (using the variable lf as the delimiter in the resulting variable):

REM NB:in a batch file, need to use %%i not %i
setlocal EnableDelayedExpansion
SET lf=-
FOR /F "delims=" %%i IN ('dir \ /b') DO if ("!out!"=="") (set out=%%i) else (set out=!out!%lf%%%i)
ECHO %out%

To capture a piped expression, use ^|:

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"
Nonsuch answered 20/9, 2008 at 15:37 Comment(6)
As with @PabloG's answer, this will only work to get the last line of output from the command, "date /t" in this case.Mcglone
I found your answer to work only when I used double percentage signs, i.e. FOR /F "delims=" %%i IN ('date /t') DO set today=%%iSippet
@Rabarberski: If you type a for command straight on the command line, you use a single %. If you use it in a batch file, you use %%.Chook
@tardate: Could you please tell how the script will look like, if command needs to be passed argument with %, for example: for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%iRale
@Rale answering 3 years late, but yes you use %%i, however that command you typed is not valid due to the date formatting inside the parentheses.Prattle
@Prattle The command is valid provided that date command used comes from Cygwin. I agree I should have mentioned that.Rale
C
44

If you have to capture all the command output you can use a batch like this:

@ECHO OFF
IF NOT "%1"=="" GOTO ADDV
SET VAR=
FOR /F %%I IN ('DIR *.TXT /B /O:D') DO CALL %0 %%I
SET VAR
GOTO END

:ADDV
SET VAR=%VAR%!%1

:END

All output lines are stored in VAR separated with "!".

But if only a single-line console-output is expected, try:

@ECHO off
@SET MY_VAR=
FOR /F %%I IN ('npm prefix') DO @SET "MY_VAR=%%I"

@REM Do something with MY_VAR variable...

@John: is there any practical use for this? I think you should watch PowerShell or any other programming language capable to perform scripting tasks easily (Python, Perl, PHP, Ruby)

Crysta answered 20/9, 2008 at 16:23 Comment(6)
The single line answer will solve the specific case I have. I just figured there was a multi-line option (or an easier single line option). I guess the capabilities of bat files just aren't that great. The need for it is for bat scripts wrapping Java apps. Building classpaths mainly.Mcglone
Be very careful with that. GWT also tried to use batch files for starting Java with specific classpaths, which failed horrible as soon as you're getting to directories with non-ASCII characters (in that case it was my home :)). They since rewrote that with VBS.Celindaceline
is there any practical use for this? Are You kidding? This is used all the time in other shells (all GNU/Linux ones I guess) and it's very useful.Ulrica
@PiotrDobrogost I think what he was trying to say was that bash scripts are a horrible relic of the past (You need to use a for loop just to capture the output of a program? Seriously?), and if you ever get to the point where you find yourself needing to use variables, you should use something more modern like PowerShell.Minutely
There is a practical use, actually... kinda. I want to use a PowerShell script to find a particular Visual Studio path, but the thing I need out of that path is a batch file that sets a bunch of env vars so I can call editbin... So I need to find the path and get it back out to the calling instance of cmd so I can run it there. ...Yes, this is as terrible as sounds. Visual Studio makes me want to cry sometimes. @Minutely I think you meant to say that batch scripts are a horrible relic of the past. ;)Honeysweet
If the command had been simple (without space), you could have done set var=%command%Chump
F
28

To get the current directory, you can use this:

CD > tmpFile
SET /p myvar= < tmpFile
DEL tmpFile
echo test: %myvar%

It's using a temp-file though, so it's not the most pretty, but it certainly works! 'CD' puts the current directory in 'tmpFile', 'SET' loads the content of tmpFile.

Here is a solution for multiple lines with "array's":

@echo off

rem ---------
rem Obtain line numbers from the file
rem ---------

rem This is the file that is being read: You can replace this with %1 for dynamic behaviour or replace it with some command like the first example i gave with the 'CD' command.
set _readfile=test.txt

for /f "usebackq tokens=2 delims=:" %%a in (`find /c /v "" %_readfile%`) do set _max=%%a
set /a _max+=1
set _i=0
set _filename=temp.dat

rem ---------
rem Make the list
rem ---------

:makeList
find /n /v "" %_readfile% >%_filename%

rem ---------
rem Read the list
rem ---------

:readList
if %_i%==%_max% goto printList

rem ---------
rem Read the lines into the array
rem ---------
for /f "usebackq delims=] tokens=2" %%a in (`findstr /r "\[%_i%]" %_filename%`) do set _data%_i%=%%a
set /a _i+=1
goto readList

:printList
del %_filename%
set _i=1
:printMore
if %_i%==%_max% goto finished
set _data%_i%
set /a _i+=1
goto printMore

:finished

But you might want to consider moving to another more powerful shell or create an application for this stuff. It's stretching the possibilities of the batch files quite a bit.

Footer answered 20/9, 2008 at 15:39 Comment(2)
Is there a variation that will work to capture multiple lines from the command?Mcglone
To get the current directory you can use echo %CD%Heald
H
9

you need to use the SET command with parameter /P and direct your output to it. For example see http://www.ss64.com/nt/set.html. Will work for CMD, not sure about .BAT files

From a comment to this post:

That link has the command "Set /P _MyVar=<MyFilename.txt" which says it will set _MyVar to the first line from MyFilename.txt. This could be used as "myCmd > tmp.txt" with "set /P myVar=<tmp.txt". But it will only get the first line of the output, not all the output

Hygroscopic answered 20/9, 2008 at 15:22 Comment(2)
That link has the command "Set /P _MyVar=<MyFilename.txt" which says it will set _MyVar to the first line from MyFilename.txt. This could be used as "myCmd > tmp.txt" with "set /P myVar=<tmp.txt". But it will only get the first line of the output, not all the output.Mcglone
This answer is for begginners like myselfMcwhorter
S
5

I would like to add a remark to the above solutions:

All these syntaxes work perfectly well IF YOUR COMMAND IS FOUND WITHIN THE PATH or IF THE COMMAND IS A cmdpath WITHOUT SPACES OR SPECIAL CHARACTERS.

But if you try to use an executable command located in a folder which path contains special characters then you would need to enclose your command path into double quotes (") and then the FOR /F syntax does not work.

Examples:

$ for /f "tokens=* USEBACKQ" %f in (
    `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" Hello '"F:\GLW7\Distrib\System\Shells and scripting"'`
) do echo %f
The filename, directory name, or volume label syntax is incorrect.

or

$ for /f "tokens=* USEBACKQ" %f in (
      `"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'F:\GLW7\Distrib\System\Shells' is not recognized as an internal or external command, operable program or batch file.

or

`$ for /f "tokens=* USEBACKQ" %f in (
     `""F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello World" "F:\GLW7\Distrib\System\Shells and scripting"`
) do echo %f
'"F:\GLW7\Distrib\System\Shells and scripting\f2ko.de\folderbrowse.exe"" "Hello' is not recognized as an internal or external command, operable program or batch file.

In that case, the only solution I found to use a command and store its result in a variable is to set (temporarily) the default directory to the one of command itself :

pushd "%~d0%~p0"
FOR /F "tokens=* USEBACKQ" %%F IN (
    `FOLDERBROWSE "Hello world!" "F:\GLW7\Distrib\System\Layouts (print,display...)"`
) DO (SET MyFolder=%%F)
popd
echo My selected folder: %MyFolder%

The result is then correct:

My selected folder: F:\GLW7\Distrib\System\OS install, recovery, VM\
Press any key to continue . . .

Of course in the above example, I assume that my batch script is located in the same folder as the one of my executable command so that I can use the "%~d0%~p0" syntax. If this is not your case, then you have to find a way to locate your command path and change the default directory to its path.

NB: For those who wonder, the sample command used here (to select a folder) is FOLDERBROWSE.EXE. I found it on the web site f2ko.de (http://f2ko.de/en/cmd.php).

If anyone has a better solution for that kind of commands accessible through a complex path, I will be very glad to hear of it.

Gilles

Sherburne answered 17/1, 2018 at 16:29 Comment(2)
You can prefix your command with CALL. FOR /F doesn't work if path has spacesVerniavernice
@Verniavernice : THANK YOU SO MUCH ! Now my code <CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters"> works perfectly.Sherburne
C
4

Example to set in the "V" environment variable the most recent file

FOR /F %I IN ('DIR *.* /O:D /B') DO SET V=%I

in a batch file you have to use double prefix in the loop variable:

FOR /F %%I IN ('DIR *.* /O:D /B') DO SET V=%%I
Crysta answered 20/9, 2008 at 15:27 Comment(1)
I have seen this approach before, but it seems really hacky. It also has the problem that it only will capture the last line of output from the command in the variable.Mcglone
G
3

Just use the result from the FOR command. For example (inside a batch file):

for /F "delims=" %%I in ('dir /b /a-d /od FILESA*') do (echo %%I)

You can use the %%I as the value you want. Just like this: %%I.

And in advance the %%I does not have any spaces or CR characters and can be used for comparisons!!

Gebelein answered 30/4, 2014 at 10:29 Comment(0)
D
2

If you're looking for the solution provided in Using the result of a command as an argument in bash?

then here is the code:

@echo off
if not "%1"=="" goto get_basename_pwd
for /f "delims=X" %%i in ('cd') do call %0 %%i
for /f "delims=X" %%i in ('dir /o:d /b') do echo %%i>>%filename%.txt
goto end

:get_basename_pwd
set filename=%~n1

:end
  • This will call itself with the result of the CD command, same as pwd.
  • String extraction on parameters will return the filename/folder.
  • Get the contents of this folder and append to the filename.txt

[Credits]: Thanks to all the other answers and some digging on the Windows XP commands page.

Dreibund answered 20/9, 2008 at 16:52 Comment(0)
H
2
@echo off

ver | find "6.1." > nul
if %ERRORLEVEL% == 0 (
echo Win7
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)

ver | find "5.1." > nul
if %ERRORLEVEL% == 0 (
echo WinXP
for /f "delims=" %%a in ('DIR "C:\Program Files\Microsoft Office\*Outlook.EXE" /B /P /S') do call set findoutlook=%%a
%findoutlook%
)
echo Outlook dir:  %findoutlook%
"%findoutlook%"
Husted answered 6/10, 2012 at 0:24 Comment(1)
Thanks for posting an answer! While a code snippet could answer the question it's still great to add some addition information around, like explain, etc ..Millibar
O
1

You can capture all output in one variable, but the lines will be separated by a character of your choice (# in the example below) instead of an actual CR-LF.

@echo off
setlocal EnableDelayedExpansion
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
)
echo directory contains:
echo %DIR%

Second version, if you need to print the contents out line-by-line. This takes advanted of the fact that there won't be duplicate lines of output from "dir /b", so it may not work in the general case.

@echo off
setlocal EnableDelayedExpansion
set count=0
for /f "delims=" %%i in ('dir /b') do (
    if "!DIR!"=="" (set DIR=%%i) else (set DIR=!DIR!#%%i)
    set /a count = !count! + 1
)

echo directory contains:
echo %DIR%

for /l %%c in (1,1,%count%) do (
    for /f "delims=#" %%i in ("!DIR!") do (
        echo %%i
        set DIR=!DIR:%%i=!
    )
)
Oidium answered 20/9, 2008 at 16:33 Comment(0)
E
1
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

the result is 'TXT: hola'

Erda answered 13/2, 2019 at 12:59 Comment(0)
U
0

You should use the for command, here is an example:

@echo off
rem Commands go here
exit /b
:output
for /f "tokens=* useback" %%a in (`%~1`) do set "output=%%a"

and you can use call :output "Command goes here" then the output will be in the %output% variable.

Note: If you have a command output that is multiline, this tool will set the output to the last line of your multiline command.

Undersurface answered 19/3, 2019 at 16:40 Comment(0)
A
-2

Please refer to this http://technet.microsoft.com/en-us/library/bb490982.aspx which explains what you can do with command output.

Antisepticize answered 20/9, 2008 at 15:21 Comment(2)
That article just covers redirection and related topics. It doesn't answer the question of how to take the output of one command and get it into a variable.Mcglone
Using his answer i have came up with this: git pull>0 set /P RESULTVAR=<0 edit: I guess, i don't know how to use line breaks here... each command is on it's own line.Balcke

© 2022 - 2024 — McMap. All rights reserved.