shell 脚本在没有 #!(sha-bang line) 的情况下仍然可以工作

use*_*213 11 bash shell-script

我是 shell 脚本的新手,很多书都写过在脚本开始时使用 #!(sha-bang) 行来调用解释器。这将为脚本调用一个新的 shell 并逐行进行解释。但是一个我的基本脚本仍然在没有魔术线的情况下运行。

所以我的问题是:

  • 我的基本脚本从哪里获得解释器。
  • 脚本是如何找到解释器的。

现在让我告诉你我的基本脚本,它只包含以下行:

echo "没有魔线的基本脚本"

Gil*_*il' 8

当你执行一个程序时,内核会检查它是否以某种神奇的字节序列开始。如果可执行文件以 开头#!,则内核将该行的其余部分解释为解释器名称。如果可执行文件以\177ELF(其中\177是字节 127)开头,则将文件加载为ELF可执行文件;这是当今大多数 unix 系统上的正常类型。

如果内核不能识别文件格式,它会拒绝执行文件并返回错误 ENOEXEC(Exec 格式错误)。当 shell 注意到这一点时,它会自行将程序作为 shell 脚本执行。

要见证这一过程,请在脚本中添加一些命令:

ps l $$
ls -l /proc/$$/exe
echo hello
Run Code Online (Sandbox Code Playgroud)

(这是针对 Linux 的,针对其他 unice 进行调整。)然后尝试从各种 shell 运行该脚本。您会看到一些 shell 产生一个新的自身实例来执行脚本(bash、ksh93),而另一些则产生/bin/sh(dash、pdksh、zsh)。

  • @EmanuelBerg 是的(实际上我应该写`ls -l /proc/$$/exe`)。`exe` 链接指向正在执行您的脚本的 shell。当您运行脚本时,您会看到解释脚本的是 bash。如果你从例如 pdksh 运行它,它会运行 `/bin/sh`。我不知道在这种情况下有任何使用 `SHELL` 环境变量或登录 shell 的 shell。 (2认同)
  • @user1678213 更改`/etc/passwd` 中的shell 会更改通过SSH 或文本控制台登录时执行的shell。它不会改变哪个 shell 可以执行脚本。 (2认同)
  • @user1678213 我通过运行测试验证了我在这里写的内容。我测试过的 shell 都没有查看 `/etc/passwd` 来决定使用哪个 shell,它们要么派生一个自己的实例,要么执行 `/bin/sh`。 (2认同)

Gur*_*uru 3

如果未提供 magic line,则使用默认 shell 来运行脚本。这个默认 shell 可以是 Bourne shell (sh),在某些风格中就是这种情况,但是,在其他一些风格中,使用的默认 shell 与执行它的登录 shell 相同。问题是:不要让系统来决定 shell,始终在第一行提供您想要的 shell。

  • 这是不正确的,它从来不是用来执行它的_“登录 shell”_。但可能发生的情况是,调用 shell(如果从 shell 调用脚本)可能有一个子 shell 来解释它。 (4认同)
  • @vonbrand这是一个常见的误解。POSIX 并不强制要求 POSIX shell 为“/bin/sh”,而只是在探索符合路径时找到的第一个“sh”可执行文件。 (2认同)