如何过滤 cl.exe 的输出但保留 success/error 代码?
How to filter output from cl.exe but preserve success/error code?
相关:Prevent cl.exe from printing the compiled source file
我想从编译器输出中过滤掉“.cpp”,但不过滤掉任何编译器错误。我可以这样做:
cl -nologo source.cpp | findstr /V /X "source.cpp"
但这有两个问题:
- 如果编译器输出的唯一行是文件名,
findstr
returns 一个失败代码。
cl.exe
调用的错误级别丢失。
我可以毫不费力地解决第一个问题,但我不确定如何在不使用临时文件的情况下解决第二个问题(我想避免!)。
在这种情况下使用临时文件可能是避免代码过于复杂的更好选择。
然而,如果你真的需要避免使用临时文件,那么你可以在管道中获取 cl 的 errorlevel
但随后要捕获该值并在你的主代码中使用它,你需要使用 FOR /F
为了捕获 findstr 的输出和 cl 的 errorlevel
.
获取管道内的 errorlevel
值本身就够棘手了,因为管道的子 cmd 在调用 cl
之前会扩展 %errorlevel%
,并且当管道的子命令嵌套在 FOR /F
的子命令中。
@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_errorlevel:
是因为它足够独特,可以与 cl 的其他输出区分开来。
findstr 中的 errorlevel
应该无关紧要,您可以根据 cl_errorlevel
采取行动
更新
我从评论中采纳了 aschipfl 的优秀建议,不使用 ###cl_errorlevel
前缀,并以更简单的方式重新实现了代码,这完全依赖于 errorlevel
来自cl
是 FOR /F
返回的最后一行
@echo off
setlocal DisableDelayedExpansion
set "errorlevel="
set "_errorlevel=errorlevel"
set "__errorlevel=_errorlevel"
set "line="
for /F "delims=" %%A in ('
^( cl -nologo source.cpp ^& call set /p "=%%%%%%__errorlevel%%%%%%"^<nul ^) ^| findstr /V /X "source.cpp"
') do (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
set "line=%%A"
)
set "cl_errorlevel=%line%"
echo,
echo cl_errorlevel:%cl_errorlevel%
pause
cl
输出的开头会有一个额外的空行,我不认为这是不需要的东西,但如果真的需要删除它,那么可以用这样的 IF
语句完成:
if defined line (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)
相关:Prevent cl.exe from printing the compiled source file
我想从编译器输出中过滤掉“.cpp”,但不过滤掉任何编译器错误。我可以这样做:
cl -nologo source.cpp | findstr /V /X "source.cpp"
但这有两个问题:
- 如果编译器输出的唯一行是文件名,
findstr
returns 一个失败代码。 cl.exe
调用的错误级别丢失。
我可以毫不费力地解决第一个问题,但我不确定如何在不使用临时文件的情况下解决第二个问题(我想避免!)。
在这种情况下使用临时文件可能是避免代码过于复杂的更好选择。
然而,如果你真的需要避免使用临时文件,那么你可以在管道中获取 cl 的 errorlevel
但随后要捕获该值并在你的主代码中使用它,你需要使用 FOR /F
为了捕获 findstr 的输出和 cl 的 errorlevel
.
获取管道内的 errorlevel
值本身就够棘手了,因为管道的子 cmd 在调用 cl
之前会扩展 %errorlevel%
,并且当管道的子命令嵌套在 FOR /F
的子命令中。
@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_errorlevel:
是因为它足够独特,可以与 cl 的其他输出区分开来。
findstr 中的 errorlevel
应该无关紧要,您可以根据 cl_errorlevel
更新
我从评论中采纳了 aschipfl 的优秀建议,不使用
###cl_errorlevel
前缀,并以更简单的方式重新实现了代码,这完全依赖于 errorlevel
来自cl
是 FOR /F
返回的最后一行
@echo off
setlocal DisableDelayedExpansion
set "errorlevel="
set "_errorlevel=errorlevel"
set "__errorlevel=_errorlevel"
set "line="
for /F "delims=" %%A in ('
^( cl -nologo source.cpp ^& call set /p "=%%%%%%__errorlevel%%%%%%"^<nul ^) ^| findstr /V /X "source.cpp"
') do (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
set "line=%%A"
)
set "cl_errorlevel=%line%"
echo,
echo cl_errorlevel:%cl_errorlevel%
pause
cl
输出的开头会有一个额外的空行,我不认为这是不需要的东西,但如果真的需要删除它,那么可以用这样的 IF
语句完成:
if defined line (
setlocal EnableDelayedExpansion
echo(!line!
endlocal
)