【问题标题】:bash: redirect (and append) stdout and stderr to file and terminal and get proper exit statusbash:将标准输出和标准错误重定向(并附加)到文件和终端并获得正确的退出状态
【发布时间】:2010-03-09 22:41:18
【问题描述】:

要将 stdout 和 stderr 重定向(并附加)到文件,同时在终端上显示它,我这样做:

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

但是,是否有其他方法可以让我获得退出状态的准确值?

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

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

【问题讨论】:

标签: bash stdout stderr tee


【解决方案1】:

也许您可以将 PIPESTATUS 的退出值放入 $?

command 2>&1 | tee -a file.txt ; ( exit ${PIPESTATUS} )

【讨论】:

    【解决方案2】:

    另一种可能性,带有一些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】:

      有一种神秘的 POSIX 方式可以做到这一点:

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

      它将变量R设置为command1的返回值,并将command1的输出通过管道传递给command2,其输出被重定向到父shell的输出。

      【讨论】:

        【解决方案4】:

        使用进程替换:

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

        tee 在子shell 中运行,所以 $?持有command的退出状态。

        【讨论】:

          猜你喜欢
          • 2010-10-26
          • 2012-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-12
          相关资源
          最近更新 更多