Contents

return和exit命令之间的差异

1. 概述

returnexit命令用于类似的目的 。一般来说,return的目的是退出Bash 函数,而exit的目的是退出Bash 脚本

在本教程中,我们将使用几个示例来讨论这两个命令之间的区别。

2. return命令

** return停止 Bash 函数的执行。**

如果我们为return提供一个整数参数,它会将该参数作为退出状态返回给函数调用者。否则,它将返回函数调用者之前执行的最后一个命令的退出状态。

2.1. 使用return退出 Bash 函数

让我们使用以下 Bash 脚本examine_return.sh检查return的行为:

#!/bin/bash
foo()
{
  if [ ! –z “$1” ]
  then
    return $1
  fi
  ls /non_existing_file >& /dev/null
  return 
}
foo 5
echo “The return value of \”foo 5\” : $?”
 
foo
echo “The return value of \”foo\”   : $?”

此脚本中的*foo()函数检查我们是否使用if [ ! –z “$1” ]*语句。

如果我们将参数传递给foo()函数,则条件表达式变为真。在这种情况下,该函数只是停止执行并使用return $1语句将作为参数传递给调用者的值返回。

如果我们不向foo()函数传递参数,则条件表达式[ ! –z “$1” ]变为假。在这种情况下,执行跳转到ls /non_existing_file >& /dev/null语句。如果文件不存在,ls命令返回*2 *。

然后我们退出foo()函数调用return而不带任何参数。事实上,显式调用return是多余的,因为它是函数中的最后一个命令。

最后,我们在脚本中调用了两次foo()函数。在第一次调用中,我们通过将参数5传递给它来调用它。在第二次调用中,我们在不传递任何参数的情况下调用它。我们使用echo命令和*$?* 在这两种情况下。

让我们运行脚本examine_return.sh并查看结果:

$ examine_return.sh
The return value of ”foo 5” : 5
The return value of ”foo”   : 2

如我们所见,结果符合预期。第一个函数调用的退出状态是5,因为我们将5作为参数传递给函数。另一方面,第二个函数调用的退出状态为2,因为这是ls /non_existing_file >& /dev/null命令的退出状态,这是退出函数之前执行的最后一个命令。

2.2. 使用return退出 Bash 脚本

如果我们使用return退出脚本怎么办?让我们使用examine_return_from_script.sh 来尝试一下,它是我们看到的前一个版本的略微修改版本:

#!/bin/bash
foo()
{
  if [ ! –z “$1” ]
  then
    return $1
  fi
  ls /non_existing_file >& /dev/null
  return 
}
foo 5
echo “The return value of \”foo 5\” : $?”
 
foo
echo “The return value of \”foo\”   : $?”
return 0

这个修改后的脚本版本与之前的脚本相同,只是增加了一个——脚本末尾的最后一个*return语句。*让我们运行这个脚本:

$ examine_return_from_script.sh
The return value of "foo 5" : 5
The return value of "foo"   : 2
examine_return_from_script.sh: line 20: return: can only ‘return’ from a function or sourced script

我们遇到了一个错误,所以我们不能使用return退出脚本。

但是,正如脚本的输出所示,我们可以使用source命令运行脚本:

$ source examine_return_from_script.sh
The return value of ”foo 5” : 5
The return value of ”foo”   : 2
$ echo $?
0

从输出中可以明显看出,脚本的退出状态为0,这是return 0的结果。

3. exit命令

**我们使用exit从 Bash 脚本中退出。**我们在脚本中的什么地方调用它并不重要。例如,我们可以在 Bash 函数内部或外部调用exit

类似于return,它可能需要一个整数参数。在这种情况下,脚本退出时退出状态设置为整数参数。如果我们不向exit传递参数,它将退出,退出状态设置为exit之前执行的最后一个命令的退出状态。

3.1. 在 Bash 函数中使用exit

让我们使用以下脚本examine_exit.sh检查 Bash 函数中exit的行为:

#!/bin/bash
foo()
{
  if [ ! –z “$1” ]
  then
    exit $1
  fi
  ls /non_existing_file >& /dev/null
  exit
}
if [ ! –z “$1” ]
then
  foo $1
else
  foo
fi
echo “This line will not be printed”

此脚本中的foo()函数与examine_return.sh中的函数非常相似。我们只是用exit命令替换了return命令。我们还在脚本的末尾添加了一个echo命令,以证明脚本在exit后立即退出。

稍后,我们在脚本中调用*foo()函数。如果我们通过向脚本传递参数来运行脚本,我们通过向函数传递相同的参数来调用foo()函数。如果我们不带任何参数运行脚本,我们将调用不带任何参数的foo()*函数。

现在,让我们运行脚本:

$ examine_exit.sh 6
$ echo $?
6
$ examine_exit.sh
$ echo $?
2

在脚本的第一次执行中,它以退出状态6退出。在第二次执行中,不带任何参数,脚本以退出状态2 退出,这是退出前ls命令的退出状态。

由于我们在foo()函数调用中立即退出了脚本,因此两次运行中的echo命令都没有输出。

3.2. 在 Bash 函数外使用exit

我们还展示了我们可以在 Bash 函数外部使用exit来退出脚本。我们有以下脚本examine_exit_anywhere.sh

#!/bin/bash
echo “This line will be printed”
exit 0
echo “But this line will not be printed”
foo()
{
  if [ ! –z “$1” ]
  then
    exit $1
  fi
  ls /non_existing_file >& /dev/null
  exit
}
if [ ! –z “$1” ]
then
  foo $1
else
  foo
fi
echo “This line will not be printed”

该脚本与我们之前使用的脚本examine_exit.sh非常相似。我们刚刚将两个echo命令添加到脚本的开头,并在它们之间添加了exit 0命令。 让我们运行脚本:

$ examine_exit_anywhere.sh
This line will be printed
$ echo $?
0

如我们所见,第一个echo被执行了。echo后的exit 0导致脚本退出,退出状态为 0。脚本其余部分中的命令未执行。

4. 使用trap命令和exit

exitreturn的另一个区别与trap命令有关。通常,我们使用trap来处理信号,但是如果我们将 EXIT 指定为trap的信号, 则当脚本以exit退出时,将执行分配给trap的操作

让我们用以下脚本examine_trap.sh来阐明这一点:

#!/bin/bash
trap “echo This line will be printed at exit” EXIT
foo()
{
  echo “I am inside the foo function  return 0
}
foo
echo “I am outside the foo functionexit 0

脚本开头的trap只是调用echo命令。foo()函数仅打印一条消息并使用return返回。最后,在打印另一条消息后,我们使用exit退出脚本。

让我们运行脚本:

$ examine_trap.sh
I am inside the foo function
I am outside the foo function
This line will be printed at exit

正如我们所见,虽然我们在exit之前调用了return ,但trap中的消息是在exit之后打印的。因此,shell 在 EXIT 上为exit执行陷阱,但不为return执行陷阱。