在Bash中退出状态不为0时,将STDOUT重定向到STDERR

时间:2017-05-23 20:59:06

标签: bash stdout stderr

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

2 个答案:

答案 0 :(得分:3)

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

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

考虑一个类似于以下内容的包装器:

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

...调用为(如果保存为stderr-wrapper):

stderr-wrapper your-program arg1 arg2 ...

答案 1 :(得分:1)

Roundabout管道方法,需要tac和无害eval,但既不是缓冲变量,也不是临时文件。

演示脚本demo,使用echo false ; false模拟输出到 stdout 的程序,并返回错误代码“ 1 ”。

#!/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

demo概括为stderr-wrapper

  1. bash

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

    #!/bin/dash
    # Usage:  stderr-wrapper program [ args... ]
    { { "$@" ; echo $? ; } | tac ; } | \
    { read x ; eval tac 1\>\&$(((x>0)+1)) ; exit $x ; }
    
  3. bash版本如何运作:

    1. 运行违规程序,输出到 stdout
    2. 在此之后立即打印错误代码,也打印到 stdout
    3. 使用tac反转整个流,因此错误代码是第一个。 (如果流很长,则很贵。)
    4. read一行,错误代码,存储在$x
    5. eval $out数组成员,对应于输出应该到达的设备,然后使用tac将输出重新反转到该设备。