Windows 如何过滤cl.exe的输出,但保留成功/错误代码?
有关: 我想从编译器输出中过滤掉“.cpp”,但不过滤掉任何编译器错误。我可以这样做:Windows 如何过滤cl.exe的输出,但保留成功/错误代码?,windows,batch-file,command-line-tool,Windows,Batch File,Command Line Tool,有关: 我想从编译器输出中过滤掉“.cpp”,但不过滤掉任何编译器错误。我可以这样做: cl-nologo source.cpp | findstr/V/X“source.cpp” 但这有两个问题: 如果编译器的唯一输出行是文件名,findstr返回一个失败代码 cl.exe调用中的errorlevel丢失 我可以不费吹灰之力解决第一个问题,但我不知道如何在不使用临时文件的情况下解决第二个问题(我希望避免!)。在这种情况下使用临时文件可能是避免代码过于复杂的更好选择 但是,如果您确实需要避免使用
cl-nologo source.cpp | findstr/V/X“source.cpp”
但这有两个问题:
findstr
返回一个失败代码cl.exe
调用中的errorlevel丢失李>
我可以不费吹灰之力解决第一个问题,但我不知道如何在不使用临时文件的情况下解决第二个问题(我希望避免!)。在这种情况下使用临时文件可能是避免代码过于复杂的更好选择 但是,如果您确实需要避免使用临时文件,那么您可以在管道中获取cl的
errorlevel
,但为了捕获值并在主代码中使用它,您需要使用FOR/F
,以便捕获findstr的输出和cl的errorlevel
在管道中获取errorlevel
值本身就非常复杂,因为管道的子cmd将在调用cl
之前展开%errorlevel%
,并且当管道的子cmd嵌套在FOR/F
的子cmd中时会变得更加复杂
@echo off
setlocal DisableDelayedExpansion
set "errorlevel="
set "_errorlevel=errorlevel"
set "__errorlevel=_errorlevel"
for /F "delims=" %%A in ('
^( cl -nologo source.cpp ^& call echo ###cl_errorlevel:%%%%%%__errorlevel%%%%%% ^) ^| findstr /V /X "source.cpp"
') do (
set "cl_out=%%A"
setlocal EnableDelayedExpansion
if "!cl_out:~0,17!"=="###cl_errorlevel:" (
endlocal
REM delims is set to <colon> and <space>
REM <space> is used to remove trailing the space(s) in echo's output which is unavoidable
REM Alternatively <nul set /p "=Output_String" can be used to eliminate the need to use <space> as delimeter
for /F "tokens=2 delims=: " %%B in ("%%A") do set "cl_errorlevel=%%B"
) else (
endlocal
REM cl's output, filtered by findstr
echo(%%A
)
)
echo,
echo cl_errorlevel:%cl_errorlevel%
pause
在cl
输出的开头会有一个额外的空行,我不认为这是不需要的,但若确实需要删除它,那个么可以使用if
语句来完成,如下所示:
if defined line (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)
在这种情况下,使用临时文件可能是避免代码过于复杂的更好选择 但是,如果您确实需要避免使用临时文件,那么您可以在管道中获取cl的
errorlevel
,但为了捕获值并在主代码中使用它,您需要使用FOR/F
,以便捕获findstr的输出和cl的errorlevel
在管道中获取errorlevel
值本身就非常复杂,因为管道的子cmd将在调用cl
之前展开%errorlevel%
,并且当管道的子cmd嵌套在FOR/F
的子cmd中时会变得更加复杂
@echo off
setlocal DisableDelayedExpansion
set "errorlevel="
set "_errorlevel=errorlevel"
set "__errorlevel=_errorlevel"
for /F "delims=" %%A in ('
^( cl -nologo source.cpp ^& call echo ###cl_errorlevel:%%%%%%__errorlevel%%%%%% ^) ^| findstr /V /X "source.cpp"
') do (
set "cl_out=%%A"
setlocal EnableDelayedExpansion
if "!cl_out:~0,17!"=="###cl_errorlevel:" (
endlocal
REM delims is set to <colon> and <space>
REM <space> is used to remove trailing the space(s) in echo's output which is unavoidable
REM Alternatively <nul set /p "=Output_String" can be used to eliminate the need to use <space> as delimeter
for /F "tokens=2 delims=: " %%B in ("%%A") do set "cl_errorlevel=%%B"
) else (
endlocal
REM cl's output, filtered by findstr
echo(%%A
)
)
echo,
echo cl_errorlevel:%cl_errorlevel%
pause
在cl
输出的开头会有一个额外的空行,我不认为这是不需要的,但若确实需要删除它,那个么可以使用if
语句来完成,如下所示:
if defined line (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)
这令人印象深刻。实际上,为了避免编写临时文件,这有点过于复杂了,但是谢谢!美好的获取
ErrorLevel
可能会更简单一些:对于/F“delims=“%%a in(^(cl-nologo source.cpp^^^^和call echo##cl#u ErrorLevel:%%^^^^^ ErrorLevel%%^ findstr/V/X“source.cpp”do(…)
。另外,您不需要####cl#errorlevel
前缀,因为您知道errorlevel
是返回的最后一行…@aschipfl,非常感谢您花时间查看我的答案。如果可以保证^^^ErrorLevel
和^ErrorLevel
都是未定义的(不管怎么说,大多数情况下都是如此),那么这确实更简单。(我认为没有必要对符号进行额外的转义(^^^&
),它将不会被解析为带括号的管道块)。关于####cl#errorlevel
和errorlevel
在最后一行返回的事实,我重复了%cl#u errorlevel%
只是为了演示结果,但我不知道如何确定我是否在没有在屏幕上打印的情况下阅读最后一行。@aschipfl,我已经根据您的评论更新了答案。谢谢大家!@马特·钱伯斯,你可能想检查一下最新的答案。这太令人印象深刻了。实际上,为了避免编写临时文件,这有点过于复杂了,但是谢谢!美好的获取ErrorLevel
可能会更简单一些:对于/F“delims=“%%a in(^(cl-nologo source.cpp^^^^和call echo##cl#u ErrorLevel:%%^^^^^ ErrorLevel%%^ findstr/V/X“source.cpp”do(…)
。另外,您不需要####cl#errorlevel
前缀,因为您知道errorlevel
是返回的最后一行…@aschipfl,非常感谢您花时间查看我的答案。如果可以保证^^^ErrorLevel
和^ErrorLevel
都是未定义的(不管怎么说,大多数情况下都是如此),那么这确实更简单。(我认为没有必要对符号进行额外的转义(^^^&
),它将不会被解析为带括号的管道块)。关于####cl#errorlevel
和errorlevel
在最后一行返回的事实,我重复了%cl#u errorlevel%
只是为了演示结果,但我不知道如何确定我是否在没有在屏幕上打印的情况下阅读最后一行。@aschipfl,我已经根据您的评论更新了答案。谢谢大家!@Matt Chambers,您可能需要检查更新的答案。