我需要使用 MS 批处理文件将程序的输出分配给变量。
所以在 GNU Bash shell 中我会使用 VAR=$(application arg0 arg1)
。我需要使用批处理文件在 Windows 中进行类似的行为。
set VAR=application arg0 arg1
之类的东西。
类似问题
如何将命令输出设置为批处理文件中的变量
如何在 windows 的变量中获取命令的结果?
使用 Windows 批处理文件中的命令结果设置变量的值
将命令的输出设置为变量(使用管道)
将命令输出分配给批处理文件中的变量
一种方法是:
application arg0 arg1 > temp.txt
set /p VAR=<temp.txt
另一个是:
for /f %%i in ('application arg0 arg1') do set VAR=%%i
请注意,%%i
中的第一个 %
用于转义其后的 %
,并且在批处理文件而不是命令行中使用上述代码时需要。想象一下,您的 test.bat
具有以下内容:
for /f %%i in ('c:\cygwin64\bin\date.exe +"%%Y%%m%%d%%H%%M%%S"') do set datetime=%%i
echo %datetime%
作为 this previous answer 的补充,管道可以在 for 语句中使用,由插入符号转义:
for /f "tokens=*" %%i in ('tasklist ^| grep "explorer"') do set VAR=%%i
for /f "tokens=*" %i in ('tasklist ^| findstr explorer') do @echo %i
但一般来说,usebackq
应该用于处理复杂的命令。
for /f "tokens=*" %%i in ('"tasklist | grep explorer"') do set VAR=%%i
。如果命令本身没有引号,对我来说更容易。
执行以下操作时:
for /f %%i in ('application arg0 arg1') do set VAR=%%i
我收到了错误:
%%i was unexpected at this time.
为了解决这个问题,我改为使用单个 %
符号,如下所示:
for /f %i in ('application arg0 arg1') do set VAR=%i
概括:
在批处理文件中使用 %%
在批处理文件之外(在命令行上)使用 %
%%
,在命令行上的批处理文件之外需要 %
您可以使用批处理宏来简单地捕获命令输出,有点像 bash shell 的行为。
宏的用法很简单,看起来像
%$set% VAR=application arg1 arg2
它甚至适用于管道
%$set% allDrives="wmic logicaldisk get name /value | findstr "Name""
宏像数组一样使用变量并将每一行存储在单独的索引中。
在 %$set% allDrives="wmic logicaldisk
的示例中,将创建以下变量:
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>
要使用它,了解宏本身的工作原理并不重要。
完整的例子
@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
假设您的应用程序的输出是数字返回码,您可以执行以下操作
application arg0 arg1
set VAR=%errorlevel%
除了答案之外,您不能直接在 for
循环的 set 部分中使用输出重定向运算符(例如,如果您想对用户隐藏 stderror 输出并提供更好的错误消息)。相反,您必须使用插入字符 (^
) 转义它们:
for /f %%O in ('some-erroring-command 2^> nul') do (echo %%O)
参考: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
我编写了每 5 秒 ping 一次 google.com 并使用当前时间记录结果的脚本。在这里您可以找到变量“commandLineStr”的输出(带索引)
@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
一些宏将命令的输出设置为变量/
直接在命令提示符下
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 accepts arguments 作为一个函数,我认为它是在批处理文件中使用的最简洁的宏:
@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 宏
不像前面的宏那么容易阅读。
::::::::::::::::::::::::::::::::::::::::::::::::::
;;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%
使用临时文件的宏
更容易阅读,如果你有一个 SSD 驱动器,它不会那么慢,但它仍然会创建一个临时文件。
@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%##
for /f "tokens=3" %%i in ('route print ^| findstr "\<0.0.0.0\>"') do set "myVar=%%i"