如何将信息添加到流输出并捕获%ERRORLEVEL%?

时间:2018-04-20 14:46:48

标签: batch-file

我有两个脚本,foo和bar。 Foo叫吧。我需要在预先设定的时间内打印条形输出线,并从条形图中捕获%ERRORLEVEL%。我似乎无法弄清楚如何做到这两点。我进一步无法弄清楚如何准确显示时间条的执行行,只有时间条完成执行并将控制权转回foo。

foo.cmd

echo off
for /f "delims=" %%a in ('bar') do (call :log "%%a")
echo after loop error level: %ERRORLEVEL%
goto :eof

:log
echo during loop error level: %ERRORLEVEL%
echo [%time%]: %~1
goto :eof

bar.cmd

echo this is log output line 1
timeout /t 2 /nobreak > NUL
echo this is log output line 2
EXIT /B 3

此次运行的输出是:

>foo
>echo off
during loop error level: 0
during loop error level: 0
[13:24:22.21]: this is log output line 1
during loop error level: 0
during loop error level: 0
during loop error level: 0
[13:24:22.23]: this is log output line 2
during loop error level: 0
after loop error level: 0

我希望从这次运行中获得:

>foo
>echo off
during loop error level: 0
during loop error level: 0
[13:24:20.21]: this is log output line 1
during loop error level: 0
during loop error level: 0
during loop error level: 0
[13:24:22.23]: this is log output line 2 <------- this is 2 seconds later
during loop error level: 0
after loop error level: 3 <------ I got %ERRORLEVEL%

感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

main.cmd:

@echo off
setlocal

call bar 2> stderr.txt > stdout.txt
set "errorsaved=%errorlevel%"

for /f "delims=" %%A in (stdout.txt) do echo [%time%]: %%A

if %errorsaved% gtr 0 (
    echo [%time%]: ERRORLEVEL: %errorsaved%
    for /f "delims=" %%A in (stderr.txt) do echo [%time%]: ERRORINFO: %%A
)

del stderr.txt stdout.txt

bar.cmd:

@echo off
setlocal

echo some output
echo more output
>&2 echo %~nx0 failed to continue
exit /b 1

for循环中的命令不想设置errorlevel。 一个选项是将stdout和stderr保存到文件并保存errorlevel 到变量进行后期处理。

main.cmd调用bar.cmd并将流重定向到文件。 %errorlevel%的值会保存到%errorsaved%。 读取并回显文件stdout.txt。 如果bar.cmd设置errorlevel大于0,则%errorsaved% 被回显,文件stderr.txt被读取并回显。 最后删除文件。

测试输出:

[ 0:08:34.46]: some output
[ 0:08:34.46]: more output
[ 0:08:34.46]: ERRORLEVEL: 1
[ 0:08:34.46]: ERRORINFO: bar.cmd failed to continue

对于使用文件方法不是实时的时间的适当关注。 以下是与使用for循环的问题类似的测试代码。

main2.cmd:

@echo off
setlocal

for /f "delims=" %%A in ('bar2.cmd') do call :log "%%~A"

:log
echo [%time%]: %~1
goto :eof

bar2.cmd:

@echo off
setlocal enabledelayedexpansion

echo start
for /l %%A in (2 2 10) do (
    >nul timeout /nobreak /t 2
    echo %%A secs [!time!]
)

输出:

[16:37:48.10]: start
[16:37:48.11]: 2 secs [16:37:40.14]
[16:37:48.11]: 4 secs [16:37:42.16]
[16:37:48.11]: 6 secs [16:37:44.17]
[16:37:48.11]: 8 secs [16:37:46.19]
[16:37:48.11]: 10 secs [16:37:48.10]
[16:37:48.11]:

每个回声应大约为2秒。

从输出可以看出,for循环不返回stdout 实时。相反,似乎等待过程完成, 类似于管道的作用。

仅作为主脚本运行bar2.cmd会实时回显 没有任何技巧可以影响main2.cmd的输出。

答案 1 :(得分:0)

使用michael_heath的回答和Klitos Kyriacou的评论中的想法,这里是对问题第一部分的回答:

@echo off
for /f "delims=" %%a in ('bar^|powershell -noprofile -command "ForEach ($line in $Input) {Write-Output \"[$(Get-Date -Format hh:mm:ss.ff^)]: $line\"}"') do (call :log "%%a")
echo after loop error level: %ERRORLEVEL%
goto :eof

:log
echo during loop error level: %ERRORLEVEL%
echo %~1
goto :eof

我已将时间戳从:log子例程移动到bar输出到的流程。这只是回应时间戳前面的bar输出。

这留下了问题的第二部分:你如何得到错误级别。这是一个非常复杂的问题,但幸运的是dbenham in another StackOverflow post已经解决了这个问题。