如何在Windows的变量中获取命令的结果?


132

我希望在Windows批处理脚本中将命令的结果作为变量获取(请参阅 获取如何在bash中获取命令的结果以获取等效的bash脚本)。首选可在.bat文件中工作的解决方案,但也欢迎其他常见的Windows脚本解决方案。


9
约翰,很难找到这个非常有用的问题。您能否考虑添加其他短语,例如如何在Windows批处理文件中将aa 程序输出捕获到变量中?
Piotr Dobrogost,2011年

3
Google在此页面上显示第3名。
勒Nyffenegger


@MichaelFreidgeim这个问题实际上是在重复该问题之前2年提出的-但此问题有多个重复项。请参阅关于stackoverflow.com/questions/6359820/…
icc97 '17

1
@ icc97,“可能重复”是一种清理方法-关闭类似的问题,并为每个问题提供最佳答案。日期不是必需的。见meta.stackexchange.com/questions/147643/...如果你同意,它需要澄清,请投票meta.stackexchange.com/questions/281980/... 如果您看到多个副本,你应该选择一个作为规范和投票接近别人。
Michael Freidgeim

Answers:


34

如果必须捕获所有命令输出,则可以使用如下批处理:

@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

所有输出行都存储在以“!”分隔的VAR中。

@John:有实际用途吗?我认为您应该观看PowerShell或任何其他能够轻松执行脚本任务的编程语言(Python,Perl,PHP,Ruby)


单行答案将解决我的具体情况。我只是想知道有一个多行选项(或者更简单的单行选项)。我想bat文件的功能不是那么好。它需要包装Java应用程序的蝙蝠脚本。主要建立类路径。
John Meagher

对此要非常小心。GWT还尝试使用批处理文件来启动具有特定类路径的Java,一旦您进入具有非ASCII字符的目录(在这种情况下,这是我的家:),该操作就会失败。此后,他们用VBS重写了它。
乔伊(Joey)

25
有什么实际用途吗?你在开玩笑吗?这在其他shell(我猜都是GNU / Linux)中一直使用,它非常有用。
Piotr Dobrogost,2011年

1
@PiotrDobrogost我想他想说的是bash脚本是过去的可怕遗物(您需要使用for循环只是为了捕获程序的输出?是认真的吗?),如果可以的话如果您发现自己需要使用变量,则应使用PowerShell等更现代的工具。
Ajedi32

3
实际上是有实际用途的。我想使用PowerShell脚本查找特定的Visual Studio路径,但是我需要从该路径中删除的是一个批处理文件,该文件设置了一堆env var,因此我可以调用editbin ...所以我需要找到该路径并将其返回给的调用实例,cmd以便我可以在此处运行它。...是的,这和声音一样可怕。Visual Studio让我有时想哭。@ Ajedi32我想你的意思是说批处理脚本是过去的可怕遗物。;)
jpmc26 2016年

85

这些年来,谦虚指挥积累了一些有趣的功能:

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

注意 "delims="覆盖默认的空格和制表符分隔符,以便date命令的输出立即被吞噬。

要捕获多行输出,它实际上仍然可以是单行的(使用变量lf作为结果变量中的定界符):

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%

要捕获管道表达式,请使用^|

FOR /F "delims=" %%i IN ('svn info . ^| findstr "Root:"') DO set "URL=%%i"

1
与@PabloG的答案一样,在这种情况下,这只能从命令“ date / t”获取最后一行输出。
John Meagher

11
我发现只有在使用双百分号的情况下您的答案才有效,即FOR /F "delims=" %%i IN ('date /t') DO set today=%%i
Rabarberski

18
@Rabarberski:如果for直接在命令行上键入命令,则使用单个%。如果在批处理文件中使用它,请使用%%
indiv 2012年

@tardate:如果命令需要通过传递参数%,例如,请告诉脚本的外观:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
dma_k 2016年

1
@degenerate如果使用的命令date来自Cygwin ,则该命令有效。我同意我应该提到这一点。
dma_k

24

要获取当前目录,可以使用以下命令:

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

虽然它使用的是临时文件,所以它不是最漂亮的,但它确实可以工作!“ CD”将当前目录放置在“ tmpFile”中,“ SET”加载tmpFile的内容。

这是使用“数组”的多行解决方案:

@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

但是您可能要考虑迁移到另一个功能更强大的Shell或为此应用程序创建一个应用程序。它极大地扩展了批处理文件的可能性。


是否存在可以从命令中捕获多行的变体?
John Meagher's

6
要获取当前目录,您可以使用echo%CD%
Joe

9

您需要使用SET带参数的命令/P并将输出定向到该命令。例如,请参见http://www.ss64.com/nt/set.html。适用于CMD,不确定.BAT文件

从对此帖子的评论:

该链接具有命令“ Set /P _MyVar=<MyFilename.txt”,该命令说它将设置_MyVar为的第一行MyFilename.txt。可以与“ myCmd > tmp.txt”一起用作“ set /P myVar=<tmp.txt”。但是它只会得到输出的第一行,而不是所有输出


2
该链接具有命令“ Set / P _MyVar = <MyFilename.txt”,该命令表示它将_MyVar设置为MyFilename.txt的第一行。可以将其与“ set / P myVar = <tmp.txt”一起用作“ myCmd> tmp.txt”。但是它只会得到输出的第一行,而不是所有输出。
John Meagher

此答案适用于像我这样的

5

在“ V”环境变量中设置最新文件的示例

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

在批处理文件中,必须在循环变量中使用双前缀:

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

2
我以前见过这种方法,但似乎确实很棘手。它还有一个问题,那就是它将仅捕获变量中命令的输出的最后一行。
John Meagher's

3

只需使用FOR命令的结果即可。例如(在批处理文件中):

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

您可以将%%I用作所需的值。就像这样:%%I

并且预先%%I没有空格或CR字符,可以用于比较!!


2

如果您正在寻找使用命令结果作为bash中的参数提供的解决方案

然后是下面的代码:

@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
  • 这将使用与pwd相同的CD命令的结果进行调用。
  • 参数上的字符串提取将返回文件名/文件夹。
  • 获取此文件夹的内容并追加到filename.txt

[学分]:感谢所有其他答案以及Windows XP命令页面上的一些内容。


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

感谢您发布答案!虽然代码片段可以回答这个问题,它仍然很大周围添加一些附加信息,如解释,等等。
j0k

2

我想对上述解决方案加注:

如果您的命令是在路径中找到的,或者如果该命令是没有空格或特殊字符的cmdpath,则所有这些语法都可以很好地工作。

但是,如果尝试使用位于路径中包含特殊字符的文件夹中的可执行命令,则需要将命令路径括在双引号(“)中,然后FOR / F语法不起作用。

例子:

$ 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.

要么

$ 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.

要么

`$ 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.

在那种情况下,我发现使用命令并将其结果存储在变量中的唯一解决方案是(临时)将默认目录设置为命令本身之一:

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%

结果是正确的:

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

当然,在上面的示例中,我假定我的批处理脚本与我的可执行命令之一位于同一文件夹中,以便可以使用“%〜d0%〜p0”语法。如果不是您这种情况,则必须找到一种方法来定位命令路径并将默认目录更改为其路径。

注意:对于那些想知道的人,此处(用于选择文件夹)的示例命令是FOLDERBROWSE.EXE。我在网站f2ko.de(http://f2ko.de/en/cmd.php)。

如果有人对通过复杂路径可访问的这种命令有更好的解决方案,我将很高兴听到它。

吉尔斯


您可以在命令前面加上CALL如果路径包含空格,则FOR / F不起作用
jeb

@jeb:非常感谢!现在,我的代码< CALL "%SOURCEDIR%\FOLDERBROWSE" ... "quoted parameters">可以完美运行。
Gilles Maisonneuve,

1

您可以将所有输出捕获到一个变量中,但是这些行将由您选择的字符(在下面的示例中为#)代替实际的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%

第二版,如果您需要逐行打印内容。这充分利用了以下事实:“ dir / b”不会有重复的输出行,因此在一般情况下可能不起作用。

@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=!
    )
)

0
@echo off
setlocal EnableDelayedExpansion
FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
    set TXT=%%i
)
echo 'TXT: %TXT%'

结果是“ TXT:hola”


0

您应该使用for命令,这是一个示例:

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

您可以使用,call :output "Command goes here"然后输出将在%output%变量中。

注意:如果命令输出为多行,则此工具会将set输出输出到多行命令的最后一行。


-1

请参考此http://technet.microsoft.com/zh-cn/library/bb490982.aspx,其中介绍了如何使用命令输出。


1
该文章仅涉及重定向和相关主题。它没有回答如何获取一个命令的输出并将其转换为变量的问题。
John Meagher

3
使用他的答案,我想出了这个: git pull>0 set /P RESULTVAR=<0 编辑:我想,我不知道如何在这里使用换行符...每个命令都在自己的行上。
RibeiroBreno 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.