【问题标题】:How do I get the result of a command in a variable in windows?如何在 windows 的变量中获取命令的结果?
【发布时间】:2010-09-11 15:04:07
【问题描述】:

我希望将命令的结果作为 Windows 批处理脚本中的变量获取(请参阅 how to get the result of a command in bash 以获取等效的 bash 脚本)。首选可以在 .bat 文件中运行的解决方案,但也欢迎使用其他常见的 Windows 脚本解决方案。

【问题讨论】:

标签: windows scripting batch-file


【解决方案1】:

不起眼的 for 命令多年来积累了一些有趣的功能:

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"

【讨论】:

  • 与@PabloG 的回答一样,这仅适用于获取命令的最后一行输出,在这种情况下为“date /t”。
  • 我发现你的答案只有在我使用双百分号时才有效,即FOR /F "delims=" %%i IN ('date /t') DO set today=%%i
  • @Rabarberski:如果您直接在命令行上键入for 命令,则使用单个%。如果在批处理文件中使用它,则使用%%
  • @tardate:如果命令需要使用% 传递参数,请告诉脚本的外观,例如:for /f "delims=" %%i in ('date +%F_%H-%M-%S') do set now=%%i
  • @degenerate 如果使用的date 命令来自Cygwin,则该命令有效。我同意我应该提到这一点。
【解决方案2】:

如果您必须捕获所有命令输出,您可以使用这样的批处理:

@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 中。

但如果只需要单行控制台输出,请尝试:

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

@REM Do something with MY_VAR variable...

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

【讨论】:

  • 单行答案将解决我的具体情况。我只是想有一个多行选项(或更简单的单行选项)。我猜 bat 文件的功能并没有那么好。需要它是用于包装 Java 应用程序的 bat 脚本。主要是构建类路径。
  • 对此要非常小心。 GWT 还尝试使用批处理文件来启动具有特定类路径的 Java,一旦您进入具有非 ASCII 字符的目录(在这种情况下,它就是我的家 :)),它就失败了。他们后来用 VBS 重写了它。
  • 这有什么实际用途吗? 你在开玩笑吗?这一直在其他 shell 中使用(我猜都是 GNU/Linux 的),而且它非常很有用。
  • @PiotrDobrogost 我认为他想说的是 bash 脚本是过去的可怕遗迹(您需要使用 for 循环 来捕获一个程序?真的吗?),如果你发现自己需要使用变量,你应该使用更现代的东西,比如 PowerShell。
  • 有一个实际用途,其实...有点。我想使用 PowerShell 脚本来查找特定的 Visual Studio 路径,但我需要从该路径中取出一个批处理文件,它设置了一堆环境变量,因此我可以调用 editbin ...所以我需要找到路径并将其返回到cmd 的调用实例,以便我可以在那里运行它。 ...是的,这和声音一样可怕。 Visual Studio 有时让我想哭。 @Ajedi32 我认为 you 的意思是说 batch 脚本是过去的可怕遗物。 ;)
【解决方案3】:

要获取当前目录,可以这样:

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 或为这些东西创建一个应用程序。这大大扩展了批处理文件的可能性。

【讨论】:

  • 是否有可以从命令中捕获多行的变体?
  • 获取当前目录可以使用 echo %CD%
【解决方案4】:

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

来自对该帖子的评论:

该链接的命令“Set /P _MyVar=<MyFilename.txt”表示它将设置_MyVar 到第一行 来自MyFilename.txt。这可能是 用作“myCmd &gt; tmp.txt”和“set /P myVar=<tmp.txt”。但它只会 获取输出的第一行,而不是 所有输出

【讨论】:

  • 该链接具有命令“Set /P _MyVar= tmp.txt”和“set /P myVar=
  • 这个答案适合像我这样的初学者
【解决方案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

【讨论】:

  • 我以前见过这种方法,但它看起来真的很hacky。它还有一个问题是它只会捕获变量中命令的最后一行输出。
【解决方案6】:

我想对上述解决方案补充一点:

如果在路径中找到您的命令,或者如果命令是没有空格或特殊字符的 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) 上找到了它。

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

吉尔

【讨论】:

【解决方案7】:

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

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

您可以使用%%I 作为您想要的值。就像这样:%%I

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

【讨论】:

    【解决方案8】:

    如果您正在寻找Using the result of a command as an argument in 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
    
    • 这将使用 CD 命令的结果调用自身,与 pwd 相同。
    • 对参数的字符串提取将返回文件名/文件夹。
    • 获取此文件夹的内容并附加到文件名.txt

    [Credits]:感谢所有其他答案以及Windows XP commands 页面上的一些挖掘。

    【讨论】:

      【解决方案9】:
      @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%"
      

      【讨论】:

      • 感谢您发布答案!虽然代码 sn-p 可以回答这个问题,但添加一些附加信息仍然很棒,比如解释等 ..
      【解决方案10】:

      您可以在一个变量中捕获所有输出,但行将由您选择的字符(下例中的#)分隔,而不是实际的 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=!
          )
      )
      

      【讨论】:

        【解决方案11】:
        @echo off
        setlocal EnableDelayedExpansion
        FOR /F "tokens=1 delims= " %%i IN ('echo hola') DO (
            set TXT=%%i
        )
        echo 'TXT: %TXT%'
        

        结果是'TXT: hola'

        【讨论】:

          【解决方案12】:

          你应该使用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 输出到您的多行命令的最后一行。

          【讨论】:

            【解决方案13】:

            请参阅此http://technet.microsoft.com/en-us/library/bb490982.aspx,它解释了您可以使用命令输出做什么。

            【讨论】:

            • 那篇文章只涉及重定向和相关主题。它没有回答如何获取一个命令的输出并将其放入变量的问题。
            • 使用他的答案我想出了这个:git pull&gt;0 set /P RESULTVAR=&lt;0 编辑:我想,我不知道如何在这里使用换行符......每个命令都在它自己的行上。跨度>
            猜你喜欢
            • 2017-01-09
            • 2017-11-12
            • 2016-04-15
            • 1970-01-01
            • 2019-10-14
            • 2020-06-25
            • 2012-09-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多