如何从源Bash脚本返回错误

3

我对bash脚本编写相当新手。我有4个嵌套的bash脚本,但我在适当地传递第四个脚本中的错误方面遇到了麻烦。例如:

script1.sh:
  source script2.sh
  <check for error and display appropriate message>
script2.sh:
  source script3.sh param_1
  <return to script1 on error>
  source script3.sh param_2
  <return to script1 on error>
  source script3.sh param_n
  <return to script1 on error>
script3.sh
  <some processing>
  script4.sh
  echo "this statement is not reached"
  return $?
script4.sh
  <some processing>
  exit $?

我的要求是:
  1. 我需要在script1中定义一个关联数组,该数组在script2中被填充并在script3的范围内可用。我认为唯一的方法是对script2和script3进行源代码引用。
  2. script4不是源代码,因为这个脚本也可以独立于这些父脚本之外执行。

这个线程讨论了使用return语句从已经被引用的bash脚本中返回,但由于script4是执行而非被引用的,我需要退出。我不明白为什么script4中的exit语句会导致原始shell和子shell都终止?它难道不应该只退出子shell吗?

我需要查看信号和陷阱吗?

感谢任何帮助


你说的是正确的:在子shell中使用exit应该只退出该子shell。也许在执行之前在你的shell中使用set -x,并研究跟踪输出。 - gilez
1
引用文件本身并不会创建子shell,它只是读取和执行被引用的文件,就像在主脚本中一样。return从被引用的文件返回,这是一个特殊情况。exit终止进程。也许术语“子shell”让您感到困惑?子shell是执行当前shell副本的子进程,通常通过将命令放在括号( )中来创建。我在您的代码中没有看到任何子shell。 - cdarke
1
source 命令不会创建子 shell。它更像是其他语言中的 include 语句。它在当前 shell 中运行代码。如果您提供一些真实的代码,我们可以解释发生了什么。 - ccarton
1
set -e 只对那些从不检查运行任何命令的返回代码的人是一种良好的实践。只有在确切知道它如何影响脚本时,才应该使用它。我从不使用它。 - ccarton
1
@crispo,关于set -e,请参考BashFAQ #105 -- 不管它是否是良好的实践,这都是一个令人意外地有争议的辩论。 - Charles Duffy
显示剩余5条评论
2个回答

4

如果你愿意,可以一直保持set -e开启。这样,在调用脚本时,你需要更加小心,因为你知道退出状态可能为非零:

script3.sh
  <some processing>
  if script4.sh; then
    rc=0
  else
    rc=$?
  fi
  echo "script4 complete"
  return $rc

请参考https://www.gnu.org/software/bash/manual/bashref.html#index-set 我的看法是,如果你真的想因为任何错误而中止程序,使用set -e是合适的。但在这种情况下,你希望<检查错误并显示适当的消息>,显然不是这种情况。

3

最佳实践就是要明确。如果你的代码总是会被源引用,因此return将是有效的,那么简单地使用:

source foo || return

return 命令的默认值是前一个命令的退出状态码,因此不需要捕获并传递它。


如果您不确定您的脚本是被引用还是直接执行,那么情况会变得有些复杂:

source foo || { rc=$?; return "$rc" 2>/dev/null || exit "$rc" }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接