代码之家  ›  专栏  ›  技术社区  ›  rouble

bash:将stdout和stderr重定向(并追加)到文件和终端并获得正确的退出状态

  •  35
  • rouble  · 技术社区  · 15 年前

    要将stdout和stderr重定向(并追加)到文件,同时在终端上显示它,我执行以下操作:

    command 2>&1 | tee -a file.txt
    

    但是,是否有其他方法可以做到这一点,以便我得到一个准确的退出状态值?

    也就是说,如果我测试 $? ,我想查看的退出状态 command ,不是的退出状态 tee .

    我知道我可以用 ${PIPESTATUS[0]} 在这里而不是 $? ,但我正在寻找另一个不需要检查的解决方案 PIPESTATUS .

    4 回复  |  直到 9 年前
        1
  •  30
  •   Martin    15 年前

    也许您可以将pipestatus的exit值放入 $?

    command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )
    
        2
  •  6
  •   Tim Cooper    13 年前

    另一种可能性 bash 调味品,就是打开 pipefail 选项:

    管道失效

    如果设置,则管道的返回值为 最后一个(最右边)的值 使用非零退出的命令 状态,如果 管道退出成功。这个 默认情况下禁用选项。

    set -o pipefail
    ...
    command 2>&1 | tee -a file.txt || echo "Command (or tee?) failed with status $?"
    

    有人说过,只有这样才能实现 PIPESTATUS 可移植的功能(例如,它还可以与posix一起工作 sh )有点复杂,即它需要 临时文件 要将管道退出状态传播回父shell进程,请执行以下操作:

    { command 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a file.txt
    if [ "`cat \"/tmp/~pipestatus.$$\"`" -ne 0 ] ; then
      ...
    fi
    

    或者,封装以供重用:

    log2file() {
      LOGFILE="$1" ; shift
      { "$@" 2>&1 ; echo $? >"/tmp/~pipestatus.$$" ; } | tee -a "$LOGFILE"
      MYPIPESTATUS="`cat \"/tmp/~pipestatus.$$\"`"
      rm -f "/tmp/~pipestatus.$$"
      return $MYPIPESTATUS
    }
    
    log2file file.txt command param1 "param 2" || echo "Command failed with status $?"
    

    或者更一般地说:

    save_pipe_status() {
      STATUS_ID="$1" ; shift
      "$@"
      echo $? >"/tmp/~pipestatus.$$.$STATUS_ID"
    }
    
    get_pipe_status() {
      STATUS_ID="$1" ; shift
      return `cat "/tmp/~pipestatus.$$.$STATUS_ID"`
    }
    
    save_pipe_status my_command_id ./command param1 "param 2" | tee -a file.txt
    get_pipe_status my_command_id || echo "Command failed with status $?"
    
    ...
    
    rm -f "/tmp/~pipestatus.$$."* # do this in a trap handler, too, to be really clean
    
        3
  •  4
  •   johnraff    10 年前

    使用过程替换:

    command > >( tee -a "$logfile" ) 2>&1
    

    T恤是在地下室里跑的,所以$?保持退出状态 命令 .

        4
  •  3
  •   Community CDub    12 年前

    有一种神秘的POSIX方法:

    exec 4>&1; R=$({ { command1; echo $? >&3 ; } | { command2 >&4; } } 3>&1); exec 4>&-
    

    它将设置变量 R 返回值为 command1 ,和管道输出 命令1 command2 ,其输出被重定向到父shell的输出。