2017-05-23 26 views
1

当编译时间失败时,编程语言Crystal当前不写入STDERR。如果退出状态不是0并且仍然返回退出状态,我需要将STDOUT重定向到STDERR。退出状态在Bash中不为0时将STDOUT重定向到STDERR

+0

您尝试过'some_bash_command.sh 2&1'吗? – t0mm13b

+1

重新定向在**程序启动之前运行**。退出状态仅在**该程序退出后才知道。你不能回到过去。 –

回答

3

从字面上看,您的请求实际上是不可能的:重定向在命令启动之前执行,而退出状态仅在退出时才知道。

但是,您可以无条件地重定向到缓冲区,然后在知道退出状态后将该缓冲区写入stdout或stderr。

考虑类似于以下的包装:

#!/bin/sh 
if output=$("[email protected]"); then 
    printf '%s\n' "$output" 
else 
    retval=$? 
    printf '%s\n' "$output" >&2 
    exit "$retval" 
fi 

...援引为(如果这被保存为stderr-wrapper):

stderr-wrapper your-program arg1 arg2 ... 
+0

这太棒了!非常感谢!它对其他快乐道路没有任何副作用。 –

+0

这里*有一个警告,因为这段代码会吃掉任何可能包含在程序输出中的NULs(因为NULs不能存储在C字符串中,bash用于存储内存)。如果这是一个问题,你可能会写入一个文件。 –

+1

如果预期的输出太大,则临时文件可能更安全 –

1

回旋管的方法,这需要tac和无害eval,但既不是缓冲区变量也不是临时文件。

演示脚本demo,使用echo false ; false模拟程序,它输出到标准输出返回一个错误码“”。

#!/bin/bash 
out=([0]=/dev/stdout [1]=/dev/stderr) 
{ { echo $1 ; $1 ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$x]} ; exit $x ; } 

证明,使用annotate-output

annotate-output +'' ./demo true ; echo --- ; annotate-output +'' ./demo false 
I: Started ./demo true 
O: true 
I: Finished with exitcode 0 
--- 
I: Started ./demo false 
E: false 
I: Finished with exitcode 1 

归纳该demostderr-wrapper

  1. 对于bash

    #!/bin/bash 
    # Usage: stderr-wrapper program [ args... ] 
    out=([0]=/dev/stdout [1]=/dev/stderr) 
    { { [email protected] ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$((x>0))]} ; exit $x ; } 
    
  2. 对于POSIX壳,(这里是dash):

    #!/bin/dash 
    # Usage: stderr-wrapper program [ args... ] 
    { { "[email protected]" ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac 1\>\&$(((x>0)+1)) ; exit $x ; } 
    

bash版本是如何工作的:

  1. 运行有问题的程序,它输出到标准输出
  2. 之后立即打印错误代码,也可以标准输出
  3. 反转整个流与tac,所以错误代码是第一个。 (昂贵,如果流很长。)
  4. read一行,错误代码,存储在$x
  5. eval$out阵列成员对应于输出应该去的设备,然后用tac重新反向输出到该设备。
相关问题