Bash函数中返回和退出之间的区别

lec*_*tif 399 bash return function return-value exit

BASH函数中的returnand exit语句与退出代码有什么区别?

Die*_*lla 291

man bashreturn [n];

使函数停止执行并将n指定的值返回给其调用者.如果省略n,则返回状态是在函数体中执行的最后一个命令的状态.

......上exit [n]:

导致shell退出状态为n.如果省略n,则退出状态是最后执行的命令的状态.在shell终止之前执行EXIT上的陷阱.

编辑:

根据您对问题的编辑,关于退出代码,return与退出代码无关.退出代码用于应用程序/脚本,而不是函数.所以在这方面,唯一设置脚本退出代码的关键字(使用$?shell变量可以被调用程序捕获的那个)是exit.

编辑2:

我上次发表的声明exit引起了一些评论.它是为了区分returnexit理解OP,事实上,在程序/ shell脚本的任何给定点,exit是使用退出代码结束脚本到调用进程的唯一方法.

在shell中执行的每个命令都会产生一个本地"退出代码":它将$?变量设置为该代码,并且可以与其他运算符一起使用if, &&以有条件地执行其他命令.

$?每个命令执行都会重置这些退出代码(以及变量的值).

顺便提一下,脚本执行的最后一个命令的退出代码被用作调用进程看到的脚本本身的退出代码.

最后,函数在被调用时,作为退出代码的shell命令.函数的退出代码(在函数)通过使用来设置return.因此,当在函数return 0运行时,函数执行终止,退出代码为0.

  • @lecodesportif:当前进程/脚本**的`$?`**被限制为`exit`或该脚本执行的最后一个命令的结果.所以,如果你的最后一个脚本行是对该函数的调用,并且该函数返回50,是的,你为调用你*的进程生成的`$?`是50.但是,这不是必须的使用`return`,因为这仅限于当前脚本.只有当此函数调用是脚本的最后一句时,才会返回它.但是,`exit`总是完成脚本并将该值作为`$?`**返回给调用进程**. (11认同)
  • 不完全是.它总是从当前shell返回一个值.如果你在一个函数内部并不重要. (10认同)
  • 评论你的编辑:我可能会混淆返回值和退出代码,但是`func(){return 50; }; func; echo $?`回声50.所以`$?`shell变量似乎不仅限于`exit`. (10认同)
  • -1让我误认为"退货"与退出代码无关." 实验告诉我,函数的返回代码和脚本的退出代码之间没有功能差异. (10认同)
  • "`$?`扩展到最近执行的前台管道的退出状态." 该出口可以是以调用`exit`(或命中脚本的末尾)的形式,或者是在函数内调用`return`的形式. (8认同)
  • @DiegoSevilla我同意,你的陈述令人困惑.根据文档:http://tldp.org/LDP/abs/html/complexfunct.html#RETURNREF.特别是:"终止一个函数.一个返回命令[1]可选地接受一个整数参数,该参数作为函数的"退出状态"返回到调用脚本,并且该退出状态被赋值给变量$?." 因此,虽然你绝对正确,`return`只会设置*脚本*的退出代码,如果该函数是要在脚本中执行的最后一个命令,文档清楚地定义了为函数定义的"退出状态". (3认同)
  • 这简直是​​假的.Shell函数*do*在封闭脚本的上下文中设置`$?`,如果对shell函数的调用是脚本中的最后一个操作,那么函数的返回值将是脚本的退出状态. (3认同)
  • -1表示"返回与退出代码无关" - 否否否!您可以从函数返回退出代码,这些函数及其退出代码可以像命令应用程序一样在命令列表中使用.考虑:`do_junk(){ls/tmp/bleedledorf 2>/dev/null; }; do_junk && echo found`将不会返回任何内容.`do_junk(){ls/tmp/bleedledorf 2>/dev/null; 返回0; }; do_junk && echo found`将返回*找到* (3认同)

Sie*_*geX 282

return将导致当前函数超出范围,同时exit将导致脚本在调用它的位置结束.这是一个示例程序,以帮助解释这个:

#!/bin/bash

retfunc()
{
    echo "this is retfunc()"
    return 1
}

exitfunc()
{
    echo "this is exitfunc()"
    exit 1
}

retfunc
echo "We are still here"
exitfunc
echo "We will never see this"
Run Code Online (Sandbox Code Playgroud)

产量

$ ./test.sh
this is retfunc()
We are still here
this is exitfunc()
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果在调用"retfunc"之前添加"set -e",此函数将不会打印"我们仍然在这里". (47认同)
  • 很好的例子.您还可以在`$?`中显示退出值1. (15认同)
  • 请注意,在上面的示例中,如果您使用“set -e”运行以便脚本在出现第一个错误时退出,则它将在第一个函数调用返回非零值后退出。 (4认同)
  • 但是,`echo fnord | 读x时; exitfunc; 完成; 回声"仍然在这里"`将打印"仍然在这里".似乎在这种情况下只退出`while`子shell. (3认同)
  • +1可能有用的添加:```return`将导致当前函数**或源脚本**超出范围。 (2认同)

Mik*_*e Q 52

我认为没有人真正完全回答这个问题,因为他们没有描述如何使用这两个问题.好吧我想我们知道退出会杀死脚本,无论它在哪里被调用,你也可以为它分配状态,例如退出或退出0或退出7等等.这可以用于确定如果脚本被另一个脚本调用而被强制停止的方式等.退出时足够了.

调用时返回将返回指定的值以指示函数的行为,通常为1或0.例如:

    #!/bin/bash
    isdirectory() {
      if [ -d "$1" ]
      then
        return 0
      else
        return 1
      fi
    echo "you will not see anything after the return like this text"
    }
Run Code Online (Sandbox Code Playgroud)

像这样检查:

    if isdirectory $1; then echo "is directory"; else echo "not a directory"; fi
Run Code Online (Sandbox Code Playgroud)

或者像这样:

    isdirectory || echo "not a directory"
Run Code Online (Sandbox Code Playgroud)

在此示例中,测试可用于指示是否找到目录.请注意,返回后的任何内容都不会在函数中执行.0为true但shell中的false为1,与其他prog langs不同.

有关功能的更多信息:http: //www.linuxjournal.com/content/return-values-bash-functions

注意:isdirectory功能仅用于指导目的.这不应该是您在真实脚本中执行此类选项的方式.

  • 这里的其他评论者批评Mike Q的例子,当他真的在谈论`return`陈述的行为时.确实,他的例子很简单,不能用于制作.但它很简单,所以它确实完成了他的任务.它没有错. (10认同)
  • 或者只使用`test -d $ 1`来获得相同的结果.永远不要`if <check> return return return`.`<check>`我会至少在所有语言中做同样的事情. (3认同)
  • 更加清楚地了解erik所说的内容:`isdirectory(){[ - d"$ 1"]; 你的行为与你在这里的行为完全相同:shell函数的默认返回值,无论是通过到达代码的末尾还是没有参数的`return`,都是最新命令的返回值. (3认同)

小智 30

请记住,函数是脚本的内部函数,通常使用return语句从它们调用它们.调用外部脚本完全是另一回事,脚本通常以exit语句终止.

BASH函数中的返回和退出语句与退出代码之间的差异非常小.两者都返回状态,而不是本身.状态为零表示成功,而任何其他状态(1到255)表示失败.return语句将返回到调用它的脚本,而exit语句将从遇到它的整个脚本结束.

return 0  # returns to where the function was called.  $? contains 0 (success).

return 1  # returns to where the function was called.  $? contains 1 (failure).

exit 0  # exits the script completely.  $? contains 0 (success).

exit 1  # exits the script completely.  $? contains 1 (failure).
Run Code Online (Sandbox Code Playgroud)

如果您的函数只是以没有return语句结束,则执行的最后一个命令的状态将作为状态代码返回(并将被放入$?).

请记住,返回和退出时会返回0到255之间的状态代码$?.你不能把任何东西塞进状态代码(例如返回"cat"); 不起作用.但是,脚本可以使用状态代码传回255种不同的失败原因.

您可以设置调用脚本中包含的变量,或者在函数中使用echo结果并在调用脚本中使用命令替换; 但返回和退出的目的是传递状态代码,而不是像C这样的编程语言所期望的值或计算结果.


Jur*_*raj 22

有时,您使用.或运行脚本source.

. a.sh
Run Code Online (Sandbox Code Playgroud)

如果包括exita.sh,它不会只是终止脚本,但最终你的shell会话.

如果包含returna.sh,它只是停止处理脚本.

  • 我遇到的一个很棒的技巧是对“ERR EXIT”使用“trap”函数,然后首先保存失败命令的退出代码“errCode=$?”,然后使用“return $”退出脚本(是否有来源)错误代码 || 退出 $errCode`,其中 `||` 的意思是“如果我无法返回,因为我没有找到,就退出”。 (6认同)
  • 但是当我只运行 a.sh 时,我收到一个错误`return: can only'return' from a function or sourced script`,这使得它不适合通用脚本。 (4认同)

Jyo*_*iff 6

简单来说(主要是编码中的新手),我们可以说,

`return` : exits the function,
`exit()` : exits the program(called as process while running)
Run Code Online (Sandbox Code Playgroud)

另外如果你观察到,这是非常基本的,但......

`return` : is the keyword
`exit()` : is the function
Run Code Online (Sandbox Code Playgroud)

  • 在 bash 脚本中,`exit` 与 `return` 差不多是一个函数。它们是内置命令。它们甚至不是保留字。 (3认同)

Cra*_*cks 6

OP 的问题:BASH 函数中的 return 和 exit 语句相对于退出代码有什么区别?

首先,需要澄清一些问题:

  • 不需要 (return|exit) 语句来终止 (function|shell) 的执行。当 (function|shell) 到达其代码列表末尾时,即使没有 (return|exit) 语句,它也会终止。

  • 不需要 (return|exit) 语句来从终止的 (function|shell) 传回值。每个进程都有一个内置变量,$?该变量始终具有数值。它是一个特殊变量,不能像“?=1”那样设置,但只能以特殊方式设置(见下面的*)。

    美元的价值?在(称为函数 | 子 shell)中执行的最后一个命令之后是传递回(函数调用者 | 父 shell)的值。无论执行的最后一个命令是(“return [n]”|“exit [n]”)还是简单的(“return”或恰好是被调用函数代码中的最后一个命令的其他命令)都是如此。

在上面的项目符号列表中,从“(x|y)”中选择,要么始终是第一项,要么始终是第二项,以分别获取有关函数和 return 或 shell 和 exit 的语句。

显而易见的是,它们都共享特殊变量的共同用法,以便$?在终止后向上传递值。

$?* 现在介绍一下可以设置的特殊方式:

  • 当被调用函数终止并返回到其调用者时,$? 调用者中的值将等于$?终止函数中的最终值。
  • 当父 shell 隐式或显式等待单个子 shell 并通过终止该子 shell 来释放时,$?父 shell 中的值将等于$?已终止的子 shell 中的最终值。
  • 一些内置函数可以$?根据其结果进行修改。但有些人则不然。
  • 内置函数“return”和“exit”,当后面跟着一个数字参数时,都$?用它们的参数进行设置,并终止执行。

值得注意的是,$?可以通过在子 shell 中调用 exit 来赋值,如下所示:

# (exit 259)
# echo $?
3
Run Code Online (Sandbox Code Playgroud)

  • 如果有人错过了,“exit 259”会回显为“3”,因为最终的退出值是一个字节。`259 % 256 = 3` (5认同)

fcm*_*fcm 5

  • exit终止当前流程 ; 有或没有退出代码,考虑这个系统不仅仅是一个程序功能.请注意,在采购时,exit将结束shell,但是,在运行时将只是exit脚本.

  • return从函数返回到调用后的指令,有或没有返回码.return是可选的,它隐含在函数的末尾.return只能在函数内部使用.

我想在源代码时添加它exit,在不杀死shell的情况下从函数内部编写脚本并不容易.我想,一个例子在'测试'脚本上更好

#!/bin/bash
function die(){
   echo ${1:=Something terrible wrong happen}
   #... clean your trash
   exit 1
}

[ -f /whatever/ ] || die "whatever is not available"
# now we can proceed
echo "continue"
Run Code Online (Sandbox Code Playgroud)

执行以下操作:

user$ ./test
Whatever is not available
user$
Run Code Online (Sandbox Code Playgroud)

test - 并且 - shell将关闭.

user$ . ./test
Whatever is not available
Run Code Online (Sandbox Code Playgroud)

只会test完成,提示将显示.

解决方案是将潜在的程序包含在(和中)

#!/bin/bash
function die(){
   echo $(1:=Something terrible wrong happen)
   #... clean your trash
   exit 1
}

( # added        
    [ -f /whatever/ ] || die "whatever is not available"
    # now we can proceed
    echo "continue"
) # added
Run Code Online (Sandbox Code Playgroud)

现在,在这两种情况下只会test退出.