可能的重复:
获取通过管道传输到另一个进程的退出代码
我使用以下命令行(在 makefile 中)通过 Perl 脚本将来自编译器的详细错误消息通过管道传输,该脚本将它们简化为人类可读的内容:
g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl
不幸的是,这种方法“掩盖”了命令返回的错误值g++
。 make 不知道g++
命令已经失败,因为它返回的只是perl
命令的错误结果。
有没有办法通过管道输出,并仍然保留原始错误条件?
万一它有所不同:我在运行 GNU bash 版本 2.04.0(1)-release (i686-pc-) 的 MSYS 控制台中使用 GNU Make 3.81 和 g++ (GCC) 3.4.5 (mingw-vistaspecial r3) msys)在 Windows XP 上。
答案1
我不确定 shellsh.exe
提供了什么(因为有多个 shell 为其 Windows 可执行文件使用该名称),但如果它是bash
或类似的,您可以使用该$PIPESTATUS
数组。对于你的例子,你会这样做:
g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl
echo "${PIPESTATUS[0]}"
答案2
Bash 有一个选项pipefail
:
The return status of a pipeline is the exit status of the last command,
unless the pipefail option is enabled. If pipefail is enabled, the
pipeline's return status is the value of the last (rightmost) command
to exit with a non-zero status, or zero if all commands exit success-
fully.
所以:
set -o pipefail && $GCC_COMMAND | $PERL_COMMAND
Make 为每一行执行子 shell 中的每一行,因此您需要将其添加到 gcc 行的开头。可能有一种方法可以让 make 只执行带有pipefail
set 的一个命令,但我不知道。
尝试SHELL=/bin/bash
在 Makefile 中添加(制作应该使用这个)
或者尝试:
bash -o pipefail -c "$GCC_COMMAND | $PERL_COMMAND"
答案3
在传统 shell 中,管道中第一个命令的状态根本不会报告给脚本。仅最后一个命令的状态可用,在$?
.
在 bash ≥3.0 中,当您想要做的是如果管道中的任何地方发生错误则停止,请使用该pipefail
选项。
g++ -c source.cpp -o source.o 2>&1 | perl /bin/gSTLFilt.pl
更一般地,在 bash 中,PIPESTATUS
数组概括$?
为涵盖最后一个管道中的所有命令。
$ (exit 1) | (exit 2) | (exit 3); echo ${PIPESTATUS[@]}
1 2 3
Zsh也有同样的功能,只是调用了数组pipestatus
。
% zsh -c '(exit 1) | (exit 2) | (exit 3); echo $pipestatus'
1 2 3
如果您愿意假设 bash(IIRC 是 msys 提供的 shell sh
),那么您可以使用PIPESTATUS
.如果不是,您可以安排通过管道将退出状态传递到顶层 shell,并让您的过滤器程序以它在输入的最后一行读取的状态退出,而不是将其用作正常输入。它很笨拙,但很有用。
在 makefile 中,使用临时文件是相对常见的,这里将编译器消息视为又一个中间文件。
%.otmp %.g++-log: %.cpp
g++ -c $< -o $@tmp 2>&1 >$*.g++-log
%.o: %.otmp %.g++-log
perl /bin/gSTLFilt.pl <$*.g++-log
mv $*.otmp $@