如果运行没有路径的命令,则不会创建子shell?

如果运行没有路径的命令,则不会创建子shell?

我正在读这本书“Linux 命令行和 Shell 脚本圣经“第三版。第 279 页,我在此引用:

“命令替换会创建所谓的subshell来运行封闭的命令。子 shell 是从运行脚本的 shell 生成的单独子 shell。因此,您在脚本中创建的任何变量都不可用于子 shell 命令。

如果您使用路径从命令提示符运行命令,也会创建子 shell ./,但如果您只是运行没有路径的命令,则不会创建子 shell。”

最后一句话让我很困惑。我用一个导出一些变量的简单脚本进行了测试;脚本存在后,变量不会持续存在,无论脚本是从./路径调用的,还是将脚本放入路径/usr/bin并在没有路径的情况下运行的。在我看来,它如何调用子shell并没有什么区别。

我错过了什么?

答案1

“命令替换会创建所谓的子 shell 来运行所包含的命令。子 shell 是从运行脚本的 shell 生成的单独子 shell。

这是谈论如下结构:

echo "$(date) `uname -r`"

在此示例中,我使用两种不同的子 shell 受支持符号调用两个子 shell。第一个子 shell 运行命令date,第二个子 shell 运行uname命令。echo两个子 shell 终止后,原始 shell 执行该命令。

因此,您在脚本中创建的任何变量都不适用于子shell命令。

这里作者搞反了。在调用子 shell 之前创建的变量对子 shell 是可用的。在子 shell 内部创建的变量只对子 shell 可用,子 shell 终止后变量将消失。

如果您使用 ./ 路径从命令提示符运行命令,也会创建子 shell,但如果您只是运行没有路径的命令,则不会创建子 shell。”

这里作者想表达的意思不太清楚。如果你调用一个外部命令,无论是否使用路径,都会发生以下情况:

  • shell forks 创建一个新进程。
  • 新创建的子进程执行您可能指定的任何 I/O 重定向。
  • 子进程执行外部命令,此时进程不再是 shell,而是成为外部程序。(当然可以是 shell 脚本)。

它是一个新进程,因此外部命令设置的任何变量对于父进程来说都是不可用的,就像它是一个子shell一样。

作者可能指的是以下三种情况之一:

  • 外部命令是格式不正确的脚本,在这种情况下,调用 shell 可能会通过猜测使用哪个 shell 来解释脚本来解决不正确的格式。(这种情况非常难以预测,因此我强烈建议不要依赖它。找到解释器的正确方法是#!在脚本开头有一行。)
  • 您可能正在调用内部命令,例如read,从语法上看,它类似于通过搜索找到的外部命令PATH。但即使从语法上看,它的行为也会有所不同。由于read将设置一个供后续命令使用的变量,因此read它本身必须在当前进程中发生,而无需任何fork调用。(出于性能原因,即使是可以安全地作为子进程调用的内部命令,也最好在当前进程中完成。调用fork有点昂贵。)
  • 您可能使用. file或来获取 shell 命令source file。在这种情况下file不是脚本,但有点类似。 中的所有命令file都将由当前 shell 调用,而无需先调用fork。(但当然,里面的命令file可以触发fork调用)。在这种情况下 中的任何#!行都file将被忽略,并且 由 设置的任何变量file都将可供当前 shell 使用。

相关内容