我有一个 bash 源run.sh
如下,
#!/bin/bash
if [ $# -ne 1 ]; then
exit
fi
...
当我以两种方式执行它时,会出现不同的行为。第一种方式是,
source run.sh
执行后会关闭终端。第二种方法是,
./run.sh
这将简单地完成脚本的运行,并停留在终端上。我问是否有一个命令可以退出source run.sh
和./run.sh
执行 bash 脚本。我也试过了return
,但在执行时效果不好./run.sh
。
更一般地说,我感兴趣的是为什么会发生这种情况,以及使用“source”和“.”执行脚本有什么区别?
答案1
在回答之前,我认为需要澄清一些问题。让我们分析以下三行:
source run.sh
. run.sh
./run.sh
前两行完全相同:source
实际上是 的别名.
。source
所做的是在当前上下文中执行 shell 脚本,因此调用exit
将退出 shell。
第三行(最容易让人困惑的那行)与其他行没有任何关系。只是一个路径,与或./run.sh
相同(例如)。 一定要记住,shell 中的命令是用空格分隔的。 因此,在这种情况下,命令不是,而是:这意味着将执行子 shell,并且仅对子 shell 有效。/home/user/run.sh
/usr/bin/something
.
./run.sh
exit
答案2
三种方式:
您可以将脚本放在函数中并仅使用返回。
#!/usr/bin/env bash
main() {
...
return 1
...
}
main "$@"
您可以测试该脚本是否由交互式 shell 提供。
if [[ $- = *i* ]]; then
return 1
else
exit 1
fi
可以尝试返回,如果失败则退出。
return 1 2>/dev/null || exit 1
答案3
将命令“source”视为“include”语句。它获取参数的内容并像直接运行一样运行它。在这种情况下,您的命令是带有“run.sh”参数的“source”,并且 run.sh 的执行方式与您在命令行中输入 run.sh 的内容完全一样。
当您运行 './run.sh' 时,'./run.sh' 是您的命令,它没有参数。由于此文件是纯文本而不是二进制文件,您的 shell 会在 shebang(第一行的 '#!')处查找解释器并找到 '/bin/bash'。因此您的 shell 随后会启动一个新的 bash 实例,并且 run.sh 的内容会在此新实例内运行。
在第一个实例中,当 bash 到达“exit”命令时,它会被完全执行,就像您将其输入到命令行中一样。在第二个实例中,它会在您的 shell 启动的 bash 进程中执行,因此只有这个 bash 实例会收到“exit”命令。
当您在 bash 中输入一行时,第一个空格之前的任何内容都被视为命令,而其后的任何内容都被视为参数。命令 '.' 是 'source' 的别名。当您运行 '. run.sh' 时,'.' 本身就是一个命令,因为它与参数之间有一个空格隔开。当您运行 './run.sh' 时,您的命令是 './run.sh','.' 是 run.sh 的相对路径的一部分,其中 '.' 代表您的当前文件夹。