Bash 中“source x”、“.x”和“./x”有什么区别?

Bash 中“source x”、“.x”和“./x”有什么区别?

我有一个 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.shexit

答案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 的相对路径的一部分,其中 '.' 代表您的当前文件夹。

相关内容