2017-03-09 76 views
2

我必须处理编译器,有时会输出一个虚拟错误。在这种情况下,我不希望我的构建过程被停止。相反,我只是想忽略错误并重新编译:

%o: %c 
    $(prefix) dumb_compiler -c $^ -o [email protected] $(suffix) 

我的目标是明确的东西作为$prefix$suffix忽略的仿真错误。取而代之的dumb_compiler让我们简单地考虑这个虚拟程序:

#!/usr/bin/perl 
my $i = int rand 10; 
die "Error -42\n" if $i > 5; 
die "Error -12\n" if $i % 2; 
print "$i\n"; 

Error -42发生时,我想放弃stdoutstderr又仿佛什么都没有发生再次运行该程序。在任何其他情况下,我想打印该程序将打印的内容。

我还想写在bash下面的oneliner把它放在一个Makefile配方:

while True: 
    (_exit, _stdout, _stderr) = exec(program) 
    if _exit == 0 and "Error -42" not in _stderr: 
     print(stdout=_stdout, stderr=_stderr) 
     exit(_exit) 

我目前写了这一点,但它不工作,它看起来并不像一个oneliner

#!/usr/bin/bash 
exit_status=0 
run=1 
exec 3>&1 
exec 4>&2 
while [ $run -eq 1 ]; 
do 
    run=0 
    ./program 2>&4 1>&3 
    $exit_status=$? 
    if [ $exit_status -ne 0 ] 
    then 
     &4 > grep -q "Error -42" 
     if [ $? -ne 0 ]: 
     then 
      run=1 
     fi 
    fi 
done 
3>&1 
4>&2 
3>&- 
4>&- 
exit $exit_status 

我的问题是我怎么能正确地从我的程序执行举行的stdout,stderr和退出状态,一旦我完成了它冲洗出来?

尽管如此,我仍然可以尝试使我的程序工作,但我认为我的方法是错误的,这就是为什么我更喜欢问这个问题。

回答

3

只需使用文件。重定向到其他文件句柄不会缓冲任何内容(在内存或磁盘上);他们不是这里的解决方案。

while true; do 
    ./program > /tmp/output 2> /tmp/error && break 
    exit_status=$? 
    grep -q "Error -42" /tmp/error || break 
done 
cat /tmp/output 
cat /tmp/error >&2 
exit $exit_status 

这样做的一个小缺点是标准输出和标准错误不会交错,但这不应该是一个很大的损失。当它们都写入相同的文件句柄时,它们才“正确”交错;只要您将它们分开(因为如果您想要在标准错误中仅查找Error -42,那么只需),您就失去了保留原始程序生成它们的相对顺序的能力。

+0

在你的例子中,你返回'$?'为最后一个'cat'而不是'program'的退出状态。我错了吗? – nowox

+0

另外'/ tmp/output','/ tmp/error'我对'/ tmp'目录有侵犯性。如果其他进程使用相同的文件,我注定要失败。我认为如果我用'-j10'运行我的Makefile就会发生这种情况。 – nowox

+0

@nowox那些临时文件就是例子。使用'stdout = $(mktemp)','stderr = $(mktemp)'等 – bishop