如何安全地提前退出 bash 脚本?

Posted

技术标签:

【中文标题】如何安全地提前退出 bash 脚本?【英文标题】:How to safely exit early from a bash script? 【发布时间】:2019-01-31 09:44:32 【问题描述】:

我知道在bash 脚本(例如here)中有几个关于exitreturn 的问题。

关于这个主题,但与现有问题不同,我相信,我想知道是否有“最佳实践”来安全地从bash 脚本实现“提前返回”,这样用户的当前如果他们获取脚本,则不会退出 shell。

this 之类的答案似乎基于“exit”,但如果脚本是有源的,即使用“.”(点空格)前缀运行,则该脚本在 当前 shell 中运行 的上下文,在这种情况下,exit 语句具有退出当前 shell 的效果。我认为这是一个不受欢迎的结果,因为脚本不知道它是被获取还是在子 shell 中运行 - 如果是前者,用户可能会意外地让他的 shell 消失。如果调用者来源它,是否有提前返回不退出当前 shell 的方法/最佳实践?

例如这个脚本...

#! /usr/bin/bash
# f.sh

func()

  return 42


func
retVal=$?
if [ "$retVal" -ne 0 ]; then
  exit "$retVal"
#  return $retVal # Can't do this; I get a "./f.sh: line 13: return: can only `return' from a function or sourced script"
fi

echo "don't wanna reach here"

...如果从子 shell 运行,则不会杀死我当前的 shell...

> ./f.sh 
> 

...但是如果它是来源的,它会杀死我当前的外壳:

> . ./f.sh 

想到的一个想法是将代码嵌套在代码中,这样就没有明确的exit 语句,但我的C/C++ 偏见使认为提前返回在美学上比嵌套代码更可取。还有其他真正“早退”的解决方案吗?

【问题讨论】:

问题不是“何时”,而是“如何”。如果脚本是源码的,则需要使用return。脚本是否应该在自己的过程中获取或执行都应该记录在案,而且 IMO 并没有很多用例需要让用户自行选择。 不,return 也可用于从正在获取的脚本返回。 最常见的解决方法是尝试return,如果不起作用,则使用exit。这将适用于两种情况,来源和执行。试试这个return $retVal 2>/dev/null || exit $retVal @StoneThrow, ...就为什么会出现这种情况而言——为了安全地获取资源,需要编写一个脚本,以免对调用它的 shell 产生副作用,并且需要工作即使 shell 处于非默认运行时状态。这不仅仅是调用exit——您需要对不同的IFS 值保持稳健;您需要对函数或别名覆盖命令具有鲁棒性;您需要避免修改用户的其他交互功能可能依赖的全局变量。 一般来说,尝试是没有意义的:用户没有合理的期望,即他们可以获取未明确编写和记录用于该使用模式的脚本。 【参考方案1】:

在不导致父 shell 终止的情况下退出脚本的最常见解决方案是首先尝试return。如果失败则exit

您的代码将如下所示:

#! /usr/bin/bash
# f.sh

func()

  return 42


func
retVal=$?
if [ "$retVal" -ne 0 ]; then
  return $retVal 2>/dev/null # this will attempt to return
  exit "$retVal" # this will get executed if the above failed.
fi

echo "don't wanna reach here"

您也可以使用return $retVal 2>/dev/null || exit "$retVal"

希望这会有所帮助。

【讨论】:

以上是关于如何安全地提前退出 bash 脚本?的主要内容,如果未能解决你的问题,请参考以下文章

如何提前退出javascript脚本标签?

在 Bash 脚本中,如果发生某种情况,如何退出整个脚本?

Bash 脚本:如何确保脚本在使用“或”(||) 条件调用的函数中出现任何错误时退出?

返回与 bash 脚本中返回的命令不同的退出代码

如何从主函数外部提前退出 Rust 程序?

3文件测试和bash中的变量类型+shift用法