通过所谓的shebang线将脚本绑定到特定的解释器是POSIX操作系统上众所周知的做法。 例如,如果执行了以下脚本(给定足够的文件系统权限),操作系统将启动脚本的文件名作为第一个参数的/bin/sh
解释器。 随后,shell将执行脚本中的命令,跳过shebang行,将其视为注释。
#! /bin/sh date -R echo hello world
可能的输出:
Sat, 01 Apr 2017 12:34:56 +0100 hello world
我曾经相信解释器(在这个例子中是/bin/sh
) 必须是一个本地可执行文件,不能是一个脚本本身,反过来需要另一个解释器才能启动。
不过,我继续尝试下面的实验。
使用以下保存为/tmp/interpreter.py
哑壳,…
#! /usr/bin/python3 import sys import subprocess for script in sys.argv[1:]: with open(script) as istr: status = any( map( subprocess.call, map( str.split, filter( lambda s : s and not s.startswith('#'), map(str.strip, istr) ) ) ) ) if status: sys.exit(status)
…和下面的脚本保存为/tmp/script.xyz
,
#! /tmp/interpreter.py date -R echo hello world
…我可以(使两个文件script.xyz
执行后)执行script.xyz
。
5gon12eder:/ tmp> ls -l 共8个 -rwxr-x --- 1 5gon12eder 5gon12eder 493 Jun 19 01:01 interpreter.py -rwxr-x --- 1 5gon12eder 5gon12eder 70 Jun 19 01:02 script.xyz 5gon12eder:/ tmp> ./script.xyz 星期一,19六月2017 01:07:19 +0200 你好,世界
这让我感到惊讶。 我甚至能够通过另一个脚本启动scrip.xyz
。
所以,我问的是这个:
请参阅下面的粗体文本:
这种机制允许脚本几乎可以在任何正常编译的程序中使用,包括作为完整的系统程序,甚至作为其他脚本的解释器 。 尽管如此,一些早期版本的内核支持将解释器指令的长度限制为大约32个字符(在第一次执行时只有16个字符),不能将解释器名称与指令中的任何参数分开,或者具有其他的怪癖。 此外,一些现代系统允许为了安全目的而限制或禁用整个机制(例如,许多系统上的脚本已禁用set-user-id支持)。 – WP
而这个输出从COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39
COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39
在Ubuntu 17.04盒子里头 COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39
,尤其是第#186-#189行 ,它告诉我们在Linux上有什么作用(即脚本可以是解释器,深度达到四层):
166:口译员脚本 解释器脚本是一个具有执行权限的文本文件 168-启用,其第一行是以下形式: 169- 170-#! 解释器[可选参数] 171- 解释器必须是可执行文件的有效路径名。 如果execve()的filename参数指定了一个解释器 那么口译员将会被引用, 175种: 176- 177-解释器[可选参数]文件名arg ... 178- 在这里argv是argv争论中指出的一系列词, execve()开始,从argv [1]开始。 181- 182-对于便携式使用,可选参数应该是缺席的,或者是 183-指定为一个单词(即,它不应该包含白色 184-空间); 见下面的注释。 185- 从Linux 2.6.28开始,内核允许脚本的解释器 本身就是一个剧本。 这个权限是递归的,直到一个 188-限制四次递归,这样翻译可能是一个脚本 189,这是由脚本解释,等等。 - 343:解释器脚本 344-第一行允许的最大行长度为127个字符 在线翻译脚本。 346- 347-解释器的可选参数参数的语义 348脚本在不同的实现中有所不同。 在Linux上,整个字符串 349-之后的解释器名称作为单个参数传递给 350-解释器,这个字符串可以包含空格。 怎么样- 在其他一些系统上,行为是不同的。 有些系统使用 352-终止可选参数的第一个空格。 在一些系统上, 353-解释器脚本可以有多个参数,而白色spa- 可选参数中的354-ces用于分隔参数。 355- Linux忽略脚本中的set-user-ID和set-group-ID位。
类Unix操作系统中的新可执行文件由系统调用execve
(2)启动。 execve
的手册页包括:
Interpreter scripts An interpreter script is a text file that has execute permission enabled and whose first line is of the form: #! interpreter [optional-arg] The interpreter must be a valid pathname for an executable which is not itself a script. If the filename argument of execve() specifies an interpreter script, then interpreter will be invoked with the following arguments: interpreter [optional-arg] filename arg... where arg... is the series of words pointed to by the argv argument of execve(). For portable use, optional-arg should either be absent, or be specified as a single word (ie, it should not contain white space); see NOTES below.
因此,在这些限制(类Unix,可选参数最多只有一个词)中,是的,shebang脚本是可移植的。 阅读手册页以获取更多详细信息,包括二进制可执行文件和脚本之间调用的其他差异。