额外的东西#
总能抵消尖锐的感叹吗?如:
已启用:
#!/foo/bar
残疾人:
##!/foo/bar
有没有已知的exec 可以执行 ? 的bar
情况是否\x23\x23\x21...
存在公认魔法的环境?
答案1
出色地,POSIX 标准无论如何都无话可说:
一种常见的历史实现是,execl()、execv()、execle() 和 execve() 函数对于任何无法识别为可执行文件(包括 shell 脚本)的文件返回 [ENOEXEC] 错误。当 execlp() 和 execvp() 函数遇到此类文件时,它们假定该文件是 shell 脚本,并调用已知的命令解释器来解释此类文件。现在 POSIX.1-2008 要求这样做。 execvp() 和 execlp() 的这些实现仅在命令解释器的可执行文件出现问题的极少数情况下给出 [ENOEXEC] 错误。由于这些实现,对于 execlp() 或 execvp() 没有提及 [ENOEXEC] 错误,尽管实现仍然可以给出它。
一些历史实现处理 shell 脚本的另一种方法是将文件的前两个字节识别为字符串“#!”并使用文件第一行的其余部分作为要执行的命令解释器的名称。
标准开发人员指出的一个潜在的混乱来源是进程映像文件的内容如何影响 exec 系列函数的行为。以下是所采取行动的描述:
如果进程映像文件是该系统的有效可执行文件(采用可执行且有效且具有适当权限的格式),则系统执行该文件。
如果进程映像文件具有适当的权限并且采用可执行但对该系统无效的格式(例如其他体系结构的可识别二进制文件),则这是一个错误,并且 errno 设置为 [EINVAL](请参阅后面的原理)上 [EINVAL])。
如果进程映像文件具有适当的权限但未被识别:
如果这是对 execlp() 或 execvp() 的调用,则它们会调用命令解释器,并假设进程映像文件是 shell 脚本。
如果这不是对 execlp() 或 execvp() 的调用,则会发生错误,并且 errno 将设置为 [ENOEXEC]。
你会注意到它没有指定如何3.1中的命令解释器被识别。
但在Linux,要求 shebang#!
准确开头。看man 2 execve
:
execve() executes the program pointed to by filename. filename must
be either a binary executable, or a script starting with a line of
the form:
#! interpreter [optional-arg]
并且#
是一个足够常见的评论角色,这就是为什么##!
似乎取消了 shebang 而没有任何其他效果。但是,该脚本仍将使用 执行sh
,因此即使/foo/bar
不执行,它也可能不是您所期望的。看man 3 exec
:
If the header of a file isn't recognized (the attempted execve(2)
failed with the error ENOEXEC), these functions will execute the
shell (/bin/sh) with the path of the file as its first argument. (If
this attempt fails, no further searching is done.)
我不知道有什么系统可以接受除 以外的 shebangs #!
,当然我怀疑是否##!
会受到特殊对待,但这当然是可能的 - 标准并不排除它。