在 shebang 行上传递给脚本的标志与使用set内置函数的行为是否存在差异?
例如:
#!/bin/bash -e
# do stuff
Run Code Online (Sandbox Code Playgroud)
对比
#!/bin/bash
set -e
# do stuff
Run Code Online (Sandbox Code Playgroud)
(问题不是特定于-e标志,而是针对任何此类标志的一般问题)。
显然,set [flags]只有从它设置的点开始才有效。但是在功能/行为方面还有其他区别吗?
POSIX shell 中的行为也一样吗?
在功能/行为方面还有其他区别吗?
当您的文件具有可执行权限并被执行时,内核会解析 shebang 行。
当您的文件在 shell 下执行时bash ./script.sh,shebang 只是一个注释。因此它将被忽略,并且您的脚本将使用任何调用者标志运行。将您的标志放在 shebang 之后将确保在任何一种情况下都在您的脚本中设置正确的标志。
shebang由 kernel 解析。这基本上意味着行为因内核而异,因操作系统而异。一些操作系统根本不处理shebang中的参数并忽略所有参数。例如#!/bin/sh -a -b,execl("/bin/sh", "-a -b")一些内核解析为execl("/bin/sh", "-a", "-b"). 将 shebang 行解析为可执行文件和参数是由与您的 shell 不同的一些其他代码完成的。有时,如果在#!类似#! /bin/sh实用程序之后有一个空格,则不会将其识别为有效的shebang。甚至有一个最近的linux 内核回归,shebang line 太长。
系统之间解释shebang的行为不同,因此您不能确定,因此最好set在shebang之后进行选择。
POSIX shell 中的行为也一样吗?
POSIX shell 不会(必须)解释您的shebang。如果您询问是否在 posix shell 中执行sh -e并set -e具有相同的行为,那么是的,-e命令行上的选项与set -e.
我找不到 shebang 线的规范,也找不到它应该如何在posix 规范中解释。我可以在 execve 文档中看到:
某些历史实现处理 shell 脚本的另一种方法是将文件的前两个字节识别为字符串“#!” 并使用文件第一行的剩余部分作为要执行的命令解释器的名称。
那些“历史实现”似乎在今天仍然被广泛使用。
shebang 行在exec*调用后由内核解析。但是,当你正在做sh <script>或popen或system该壳 可以(但不必)本身作为一个扩展解释家当线,而不是依赖于内核实现,从POSIX:
壳牌介绍
- 壳从文件中读取(请参阅sh)它的输入,从
?c选项或从system()和popen()在POSIX.1-200x的系统接口体积定义的函数。如果 shell 命令文件的第一行以字符“#!”开头,则结果未指定。
至于 bash,看起来 bash首先尝试 execve,然后如果找不到内核无法运行可执行文件的原因,如果文件有 shebang,则它自己解析 shebang以找出解释器。