4

这是一个蝙蝠脚本:

@ECHO 关闭

REM如何获取子进程的退出码

SETLOCAL 启用延迟扩展
FOR /F "usebackq tokens=* delims=" %%i IN (
    `^
        tracert google.com ^
        ^& 退出 /B 5 ^
    `
) 做 (
    回声 [日志] %%i
)

REM 我在这里需要的是 "EXIT_CODE:5" ,
REM 但显示“EXIT_CODE:0”,求助!
快速眼动
REM ***注意***:没有临时文件或任何非 bat 样式支持,
欢迎使用 REM 确切的方式,这里仅适用于 bat-zone。
快速眼动
ECHO EXIT_CODE:%ERRORLEVEL%

本地化

暂停

我需要捕获子进程的输出和退出代码,然后在for...in语句中处理输出。但是,退出代码没有通过:

当子进程退出时,退出代码要么在语句完成后被主进程刷新,要么一开始for...in就没有传递。

4

3 回答 3

4

FOR IN() 子句中的命令在全新的 CMD.EXE 会话中运行,因此无法直接访问 ERRORLEVEL 或命令可能设置的任何环境变量。

通常最好和最简单的解决方案是使用临时文件:

yourCommand >output.txt
set exit_code=%errorlevel%
for /f "delims=" %%i in (output.txt) do processOutput
del output.txt

但是您已声明不能使用临时文件。

唯一的选择是在 IN() 子句中回显 ERRORLEVEL,然后在 DO 子句中解析 ERRORLEVEL。回显 ERRORLEVEL 有点棘手,因为 %ERRORLEVEL% 在解析时被扩展,并且整个 IN() 子句被一次解析,因此 %ERRORLEVEL% 将始终为 0。

IN() 子句命令使用命令行上下文执行,而不是批处理上下文。新的 CMD.EXE 会话不会继承当前的延迟扩展状态 - 它默认为禁用延迟扩展。最简单的解决方案是使用 CALL 和适当的转义%ERRORLEVEL%来延迟扩展,直到您的命令执行之后。添加插入符号以转义命令上下文。然后百分比和插入符号加倍以逃避父批次 - %%^^ERRORLEVEL%%

您需要使您的 ERRORLEVEL 消息唯一,以便您的 DO 子句可以将 ERRORLEVEL 与正常输出区分开来。

@echo off
setlocal enableDelayedExpansion
for /f "delims=" %%A in ('dir DoesNotExist^&call echo ::ERROR::%%^^ERRORLEVEL%%') do (
  set "ln=%%A"
  if "!ln:~0,9!" equ "::ERROR::" (
    set "EXIT_CODE=!LN:~9!"
  ) else (
    REM normal output - do whatever
    echo %%A
  )
)
echo EXIT_CODE=%EXIT_CODE%

这是上面的一些示例输出

C:\test>test.bat
File Not Found
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11
 Directory of C:\test
EXIT_CODE=1
于 2012-10-11T12:11:33.523 回答
1

程序的退出代码可以被读取%ERRORLEVEL%。要将其分配给echo以后的变量:

set exitstatus=%ERRORLEVEL%
echo %exitstatus%

您可能会觉得Raymond Chen 的这篇文章很有趣。

于 2012-10-10T14:22:48.537 回答
0

正如 Mike Kwan 所说:评估%errorlevel%变量。由于您似乎想设置子进程的退出代码,您可以执行以下操作:

@echo off

call :trace google.com
echo EXIT_CODE:%errorlevel%

set text=
for /f "delims= tokens=*" %%l in (out.txt) do (
  set text=!text!^

%%l
)
echo !text!

goto end

:trace
tracert %1 >out.txt
exit /b 5

:end
pause

编辑:更新了代码以将输出读入变量。

于 2012-10-10T22:31:59.110 回答