【问题标题】:In bash how do I exit a script from a function that is piped by tee?在 bash 中,如何从由 tee 传递的函数中退出脚本?
【发布时间】:2015-12-20 21:07:52
【问题描述】:

我试图理解为什么每当我使用function 2>&1 | tee -a $LOG tee 时会在函数中创建一个子shell,而该子shell 无法通过简单的exit 1 退出(如果我不使用tee 它工作正常) .下面的例子:

#!/bin/bash
LOG=/root/log.log

function first()
{
echo "Function 1 - I WANT to see this."
exit 1
}

function second()
{
echo "Function 2 - I DON'T WANT to see this."
exit 1
}
first 2>&1 | tee -a $LOG
second 2>&1 | tee -a $LOG

输出:

[root@linuxbox ~]# ./1.sh  
Function 1 - I WANT to see this.
Function 2 - I DON'T WANT to see this.

所以。如果我删除 | tee -a $LOG 部分,它将按预期工作(脚本将在第一个函数中退出)。

您能否解释一下如何克服这个问题并在函数中正确退出,同时能够 tee 输出?

【问题讨论】:

  • "在函数中创建一个子shell" 好吧,你已经说过了。为什么?因为管道中除了最后一个之外的所有简单命令都在子shell中执行(最后一个取决于选项或其他东西——我忘了​​)。为什么?因为。至于如何正确退出,请查看退出状态(如果设置了pipefail)或管道后的PIPESTATUS
  • 以上评论的跟进:我忘记的选项是lastpipe
  • 4ae1e1,也谢谢你。在您的帮助下,我还了解了 PIPESTATUS,显然是解决方法:function PIPE_STAT() { if [[ $PIPESTATUS -ne 0 ]]; then exit 1 fi } 可以使用并放置在每个 function 2>&1 | tee -a $LOG 之后以验证状态并在需要时退出。

标签: bash function exit tee subshell


【解决方案1】:

如果你创建管道,函数在子shell中运行,如果你从子shellexit,只会影响子shell,不影响父shell。

printPid(){ echo $BASHPID; }

printPid #some value
printPid #same value
printPid | tee #an implicit subshell -- different value
( printPid ) #an explicit subshell -- also a different value

如果,而不是 aFunction | tee 你这样做:

aFunction > >(tee)

基本相同,除了aFunction 不会在子shell 中运行,因此将能够影响当前环境(设置变量、调用退出等)。

【讨论】:

  • 谢谢,PSkocik,这确实是需要的解决方案!
  • 当我使用aFunction > >(tee) 时出现错误。请详细说明解决方案。我没听懂吗?
  • @Makesh 你装什么壳。 >(tee) 仅适用于“高级”shell,如 bash、ksh 或 zsh。像 dash 这样的简单 POSIX shell 没有它。
【解决方案2】:

使用PIPESTATUS 检索管道中第一个命令的退出状态。

first 2>&1 | tee -a $LOG; test ${PIPESTATUS[0]} -eq 0 || exit ${PIPESTATUS[0]}
second 2>&1 | tee -a $LOG; test ${PIPESTATUS[0]} -eq 0 || exit ${PIPESTATUS[0]}

【讨论】:

    【解决方案3】:

    如果管道中的任何内容使用set -e -o pipefail 失败,您可以告诉 bash 失败:

    $ cat test.sh
    #!/bin/bash
    LOG=~/log.log
    
    set -e -o pipefail
    
    function first()
    {
    echo "Function 1 - I WANT to see this."
    exit 1
    }
    
    function second()
    {
    echo "Function 2 - I DON'T WANT to see this."
    exit 1
    }
    first 2>&1 | tee -a $LOG
    second 2>&1 | tee -a $LOG
    $ ./test.sh
    Function 1 - I WANT to see this.
    

    【讨论】:

    • 谢谢!我也喜欢这个解决方案 - 优雅,但仅适用于 bash v3 及更高版本(显然)。
    • bash v3 于 2004 年发布。我想你会没事的。
    • set -e 可能有风险。在您的脚本中,如果任何地方出现任何错误,它将中止脚本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-29
    • 2020-09-04
    • 1970-01-01
    • 2012-09-22
    • 2023-01-28
    • 2013-08-05
    相关资源
    最近更新 更多