在批处理脚本中捕获命令的输出并检查错误级别

7
我有一个命令(我们称其为command),它会打印到标准输出,并根据执行的成功或失败设置ERRORLEVEL。我想从批处理脚本中调用command,并处理command的输出,但仅当command以ERRORLEVEL 0(即成功)退出时。最好不需要临时文件或检查命令的输出以推断它是否成功。
我可以使用for语句捕获命令的输出,但在这样做时检查ERRORLEVEL会有问题。我尝试了以下内容:
for /F %%A in ('command') do (
     REM The following check does not seem to work
     if ERRORLEVEL 1 goto error
     REM otherwise, do stuff with %%A
)

我也尝试过使用%errorlevel%!errorlevel!(与setlocal enabledelayedexpansion一起),但都没有起作用。


只是出于好奇,你听说过PowerShell吗? - John Saunders
我听说过它,但还没有探索其威力。在这种情况下,我正在尝试将上述逻辑纳入现有的批处理脚本中,因此除非我可以将其用作批处理脚本和上述逻辑之间的接口,否则我更愿意不必将所有内容重写为PowerShell脚本。 - Pak
你需要捕获命令输出还是只需要退出代码(错误级别)?您是否尝试将此命令放在以下行上?IF %ERRORLEVEL% NEQ 0 goto error - sjoy
2个回答

2
使用类似以下的代码:
@echo off
"command.exe">"%TEMP%\CommandOutput.tmp"
if errorlevel 1 goto Failed

for /F "usebackq" %%A in ("%TEMP%\CommandOutput.tmp") do (
     REM Do stuff with %%A
     echo %%A
)
goto DelTempFile

:Failed
echo There was an error on executing command.

:DelTempFile
if exist "%TEMP%\CommandOutput.tmp" del "%TEMP%\CommandOutput.tmp"

这个批处理代码首先将命令的标准输出重定向到临时文件夹中的一个文件中运行。然后它评估命令的退出代码。
如果没有错误,输出将使用“for”进行处理。
如果出现错误,则显示适当的错误消息。
最后,在批处理结束之前删除捕获的输出的临时文件。

3
谢谢回复,但我正在寻找一种不需要创建临时文件的解决方案(如果可能的话)。 - Pak

2
问题在于在for命令的in子句中执行的命令在单独的cmd实例中运行,并且该实例的退出代码不会传播到do子句内的代码。

如果您需要使用for命令处理输出,并且需要do子句内生成的命令的errorlevel,则需要将两者分开并生成一个临时文件。

Mofi的答案可能是最快、最简单和最直接的解决方案,而无需涉及外部脚本引擎/PowerShell。

对于大部分代码都包含在in子句中的解决方案:

@echo off
    setlocal enableextensions disabledelayedexpansion

    rem Some commands for testing - command/uncomment as needed
    set "command=findstr 2> nul"  
    rem set "command=ping -n 1 localhost"
    rem set "command=ping -n 1 localhost | find "TTL^^^=" "

    set "el="
    for /f "delims=" %%a in ('
        cmd /v /q /c "set "t^=%temp%\%~nx0.%random%"&(>"!t!" (%command%)&echo(!errorlevel!&type "!t!"&del /q "!t!")"
    ') do if not defined el ( 
        rem The first line in the output is the exit code of the executed command
        set "el=%%a" & if %%a gtr 0 goto failed 
    ) else (
        rem Process the output of the command
        echo(%%a
    ) 
    exit /b

:failed
    echo failed with errorlevel %el%
    goto :eof

基本思路是获取执行命令输出的第一行作为错误级别,以便我们可以检查并决定是否需要更多处理。
注意:这将无法避免将所有输出加载到内存中。对于从文件检索数据而不是从命令执行中检索数据时,for /f会在开始执行do子句中的代码之前加载所有数据,并且效率更高(这也是Mofi答案更快的原因之一)。

我真的不喜欢接受这个,一定有更好的方法... - Martin Braun
更好的方式被称为PowerShell。 - JonathanDavidArndt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接