功能/行为上还有其他差异吗?
当您的文件具有可执行权限并被执行时,shebang 行将由内核解析。
当你的文件在 shell 下执行时bash ./script.sh
那么 shebang 只是一个评论。因此它将被忽略,并且您的脚本将使用任何调用者标志运行。将您的标志放在 shebang 之后将确保在任何情况下在您的脚本中设置正确的标志。
舍邦是由内核解析 https://github.com/torvalds/linux/blob/master/fs/binfmt_script.c#L42。这基本上意味着不同内核、不同操作系统的行为有所不同。有些操作系统根本不处理 shebang 中的参数并忽略所有参数。例如一些内核解析#!/bin/sh -a -b
as execl("/bin/sh", "-a -b")
一些作为execl("/bin/sh", "-a", "-b")
。将 shebang 行解析为可执行文件和参数是由与您的 shell 不同的其他代码完成的。有时如果后面有一个空格#!
like #! /bin/sh
实用程序无法将其识别为有效的 shebang。甚至最近还有一个linux 内核回归,shebang 线太长 https://lwn.net/Articles/779997/.
shebang 的解释方式因系统而异,因此您无法确定,因此最好set
shebang 之后的选项。
POSIX shell 中的行为也相同吗?
POSIX shell 并不(必须)解释你的 shebang。如果你问是否执行sh -e
and set -e
在 posix shell 中具有相同的行为,那么是的,选项-e在命令行上 https://pubs.opengroup.org/onlinepubs/9699919799/具有相同的行为set -e
.
我找不到 shebang 线的规范,也找不到它应该如何解释POSIX规范 http://www.open-std.org/jtc1/sc22/open/n4217.pdf。我可以在 execve 文档中看到:
一些历史实现处理 shell 脚本的另一种方法是将文件的前两个字节识别为字符串“#!”并使用文件第一行的其余部分作为要执行的命令解释器的名称。
这些“历史实现”今天似乎仍然被广泛使用。
shebang 行被内核解析后exec*
来电。但当你在做的时候sh <script>
or popen
or system
the shell can(但不是必须)将 shebang 行本身解释为扩展,而不依赖于 posix 的内核实现:
外壳介绍
- shell 从文件(参见 sh)中读取输入
−c
选项或从system()
and popen()
POSIX.1-200x 系统接口卷中定义的函数。如果 shell 命令文件的第一行以字符“#!”开头,则结果未指定。
至于bash,看起来像bash首先尝试执行 https://github.com/samuelcolvin/bash/blob/master/execute_cmd.c#L5457,那么如果找不到内核无法运行可执行文件的原因,如果文件有 shebang https://github.com/samuelcolvin/bash/blob/master/execute_cmd.c#L5540, then 它自己解析 shebang https://github.com/samuelcolvin/bash/blob/master/execute_cmd.c#L5331找到翻译员。