美文网首页
bash的set -e和set -o pipefail

bash的set -e和set -o pipefail

作者: CodingCode | 来源:发表于2021-10-20 05:19 被阅读0次
    1. set -e

    命令的含义是:若指令传回值不等于0,则立即退出shell。

    $ cat t.sh 
    #!/usr/bin/env bash
    set -e
    echo "0000"
    ls *.notexist
    echo "9999"
    
    $ ./t.sh 
    0000
    ls: *.notexist: No such file or directory
    
    $ echo $?
    2
    

    在shell脚本t.sh中,如果第一命令ls *.notexist执行失败了(即返回值不为零),则退出整个t.sh脚本,放气随后的其他所有命令,并且返回第一个失败命令的返回值(2就是ls *.notexist的返回值)。

    • 同时适用于函数返回值
    $ cat t.sh
    #!/usr/bin/env bash
    set -e
    
    function foo() {
      return 9
    }
    
    echo "0000"
    foo
    echo "9999"
    
    $ ./t.sh
    000
    
    $ echo $?
    9
    

    这里9是函数foo()的返回值。

    • 也适用于函数内的命令
    $ cat t.sh 
    #!/usr/bin/env bash
    set -e
    
    function foo() {
      echo "foo-000"
      ls *.notexist
      echo "foo-999"
      return 9
    }
    
    echo "0000"
    foo
    echo "9999"
    
    $ ./t.sh 
    0000
    foo-000
    ls: cannot access *.notexist: No such file or directory
    
    $ echo $?
    2
    

    这里2函数内命令ls *.notexist的返回值。我们看到函数foo()内其他的命令也都没有执行了。

    • 和子函数(sub)内的命令
    $ cat t.sh
    #!/usr/bin/env bash
    set -e
    
    function sub() {
      echo "sub-000"
      ls *.notexist
      echo "sub-999"
      return 5
    }
    
    function foo() {
      echo "foo-000"
      sub
      echo "foo-999"
      return 9
    }
    
    echo "0000"
    foo
    echo "9999"
    
    $ ./t.sh 
    0000
    foo-000
    sub-000
    ls: cannot access *.notexist: No such file or directory
    
    $ echo $?
    2
    

    可以看到即使在子函数内的命令执行返回非零值,则整个脚本t.sh就停止执行并返回那个非零值。

    1. set -o pipefail

    前面set -e的命令有一种例外,即:

    $ cat t.sh 
    #!/usr/bin/env bash
    
    set -e
    
    echo "0000"
    ls *.notexist | echo "hehe"
    echo "9999"
    
    $ ./t.sh 
    0000
    hehe
    ls: cannot access *.notexist: No such file or directory
    9999
    
    $ echo $?
    0
    

    即使ls *.notexist执行失败了返回非零值,整个脚本并没有停止,而是继续往下执行,并最终返回成功(0)。有些场合这不是我们需要的。

    原因是这里使用了pipeline,bash缺省使用pipeline的最后一个命令的返回值作为整条命令的返回值,这里最后一个命令是echo,它的执行没错误,所以bash认为所有命令都执行成功了。

    如果我们把echo 和ls换一个顺序:

    $ cat t.sh 
    #!/usr/bin/env bash
    
    set -e
    
    echo "0000"
    echo "hehe" | ls *.notexist
    echo "9999"
    
    $ ./t.sh 
    0000
    ls: cannot access *.notexist: No such file or directory
    
    $ echo $?
    2
    

    此时就触发了命令返回值非零的条件。

    命令set -o pipefail就是用来解决这个问题,就是pipeline中的命令出错了,把这个非零返回值往后传递,作为整行命令的返回值。

    $ cat t.sh
    #!/usr/bin/env bash
    
    set -e
    set -o pipefail
    
    echo "0000"
    echo "hehe---000" | ls *.notexist | echo "hehe---999"
    echo "9999"
    
    $ ./t.sh 
    0000
    hehe---999
    ls: cannot access *.notexist: No such file or directory
    
    $ echo $?
    2
    

    最后这个2就是pipe中的命令ls *.notexist的返回值。

    注意:如果一个pipeline里面有多个命令执行返回非零值,后面的会覆盖前面的,即最后一个命令的非零返回值被返回:

    #!/usr/bin/env bash
    
    set -e
    set -o pipefail
    
    function foo() {
      echo "foo-000"
      return 9
    }
    
    echo "0000"
    echo "hehe---000" | foo | ls *.notexist | echo "hehe---999"
    echo "9999"
    

    此时的返回值是2,即ls *.notexist的返回值。而:

    #echo "hehe---000" | ls *.notexist | foo | echo "hehe---999"
    

    的返回值是9,即foo()的返回值。因为他们都是整个pipe的最后一个非零返回值。

    相关文章

      网友评论

          本文标题:bash的set -e和set -o pipefail

          本文链接:https://www.haomeiwen.com/subject/yuzaoltx.html