网站搜索

了解 Bash 中的采购和分叉之间的区别


本文的主要重点是清楚地了解在 bash 中运行脚本与源脚本时会发生什么。首先,我们要清楚地了解不同方式调用脚本时程序是如何提交的。

注意:创建带有扩展名的脚本并不重要。即使没有扩展,脚本也能正常运行。

基本上,每个脚本都以名为 shebang(#!) 的行开头。 bash 中的 Hash 符号将被解释为注释,但 shebang 有特殊含义。它告诉 bash 在 shebang 中提到的任何解释器中提交程序。

下面是一个示例程序,我指定 bash 作为我的解释器。

cat >> Hello_World.sh
#!/usr/bin/env bash
echo "Hello world"

chmod +x Hello_world.sh

现在要运行该脚本,您可以通过两种方式执行。

  • 使用相对路径来调用脚本。移动到脚本所在的目录并运行./Hello_world.sh
  • 使用绝对路径来调用脚本。从文件系统中的任何位置键入脚本的完整路径。
./Hello_world.sh
pwd
/home/karthick/Hello_world

现在让我们看看当您尝试在没有 shebang 的情况下提交程序时会发生什么。如果没有 shebang,程序将提交到您当前运行的任何 shell,在我的例子中,它是 Bash (/bin/bash)。

让我演示一个例子。我正在创建一个没有 shebang 的 python 脚本,当我调用该程序时,bash 不知道它应该将此程序提交给 python 解释器,而是运行该程序在当前外壳中。

cat > run-py.py
echo $SHELL
print("Hello world")

chmod +x run-py.py
./run-py.py

在这种情况下,您可以通过提及应将程序提交到哪个解释器来调用该程序,或者仅添加始终推荐的 shebang 行。

which python3
$(which python3) /home/karthick/run_py.py

既然您知道如何调用脚本,下一步就是了解调用脚本时会发生什么。当您如上面的示例所示调用脚本时,它将创建一个子进程(forking),并且脚本将被提交给子进程。我运行了一个示例脚本,该脚本将仅运行以下命令并显示该脚本已提交给子进程。

ps -ef --forest | grep -i bash

脚本中可以有多个子进程,这取决于我们的代码。需要注意的是,下标创建的环境变量一旦完成就会被删除。子进程可以通过导出来访问父进程创建的变量。但父进程无法访问子进程创建的变量。

请参阅以下文章,了解有关变量如何工作以及如何导出变量的更多信息。

  • 在 Shell 脚本中理解和编写“Linux 变量”
  • 了解 Bash 中 $$和 $BASHPID 之间的区别

寻找脚本

Source”是一个 shell 内置命令,它读取作为参数传递给它的文件,并在当前 shell 环境中运行代码。您最常使用的适当用例是修改 .bashrc.bash_profile 中的配置,并使用 source 命令重新加载更改。

type -a source

有两种语法方法可以运行源命令。您可以从两种语法中选择任何一个,这是个人选择。

source FILE_NAME [ARGUMENTS]
. FILE_NAME [ARGUMENTS]

让我演示一下源代码的实际工作原理。我将创建两个 shell 脚本。第一个脚本(Module.sh)将保存一些变量和函数。第二个脚本(Main.sh)将打印变量并调用函数。

文件Module.sh

#!/usr/bin/env bash

VAR1=$(echo "Welcome to $1")

function f1(){
  echo “Function f1 is called”
}

文件Main.sh

#!/usr/bin/env bash

echo $VAR1
f1

设置脚本的执行权限,调用主脚本“main.sh”。现在,该脚本将尝试在当前 shell 环境中查找函数 f1 和变量 VAR1,但会失败并显示命令未找到。

bash main.sh

现在让我们在脚本中运行 source 命令,该命令会将变量和函数加载到当前 shell 环境中,并且可以通过 “main.sh ” 访问。

文件Module.sh

#!/usr/bin/env bash

VAR1=$(echo "Welcome to $1")

function f1(){
  echo "Function f1 is called"
}

文件Main.sh

#!/usr/bin/env bash

source module.sh Tecmint
echo $VAR1
f1

现在再次运行脚本并查看。

bash main.sh

sourcebash 中非常有用,可以遵循模块化编程方法来创建 shell 脚本。我们可以将代码分解成更小的模块,并可以在许多程序中使用。通过这些方式,我们可以遵循DRY不要重复自己)原则。

这就是本文的内容。我们已经简要讨论了 bash 中的源和分叉之间的区别。阅读本文并与我们分享您的宝贵反馈。