shebang 标志与设置内置标志之间的区别

P.P*_*.P. 5 bash posix sh

在 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 中的行为也一样吗?

Kam*_*Cuk 8

在功能/行为方面还有其他区别吗?

当您的文件具有可执行权限并被执行时,内核会解析 shebang 行。

当您的文件在 shell 下执行时bash ./script.sh,shebang 只是一个注释。因此它将被忽略,并且您的脚本将使用任何调用者标志运行。将您的标志放在 shebang 之后将确保在任何一种情况下都在您的脚本中设置正确的标志。

shebang由 kernel 解析。这基本上意味着行为因内核而异,因操作系统而异。一些操作系统根本不处理shebang中的参数并忽略所有参数。例如#!/bin/sh -a -bexecl("/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 -eset -e具有相同的行为,那么是的,-e命令行上的选项set -e.

我找不到 shebang 线的规范,也找不到它应该如何在posix 规范中解释。我可以在 execve 文档中看到:

某些历史实现处理 shell 脚本的另一种方法是将文件的前两个字节识别为字符串“#!” 并使用文件第一行的剩余部分作为要执行的命令解释器的名称。

那些“历史实现”似乎在今天仍然被广泛使用。

shebang 行在exec*调用后由内核解析。但是,当你正在做sh <script>popensystem 可以(但不必)本身作为一个扩展解释家当线,而不是依赖于内核实现,从POSIX:

壳牌介绍

  1. 壳从文件中读取(请参阅sh)它的输入,从?c选项或从system()popen()在POSIX.1-200x的系统接口体积定义的函数。如果 shell 命令文件的第一行以字符“#!”开头,则结果未指定。

至于 bash,看起来 bash首先尝试 execve,然后如果找不到内核无法运行可执行文件的原因,如果文件有 shebang,则它自己解析 shebang以找出解释器。


che*_*ner 5

某些操作系统可能不允许或限制在 shebang 中使用参数。set脚本本身中的命令没有这样的限制。