是通过shebang线路链接口译便携式?

通过所谓的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

所以,我问的是这个:

  • 我的实验观察到的行为是否便携?
  • 这个实验是否正确地进行了,或者是否有这种情况不起作用? 不同的(类Unix)操作系统如何?
  • 如果这应该起作用,就调用而言,真正的本地可执行文件和解释脚本之间是否存在明显差异?

  1. 请参阅下面的粗体文本:

    这种机制允许脚本几乎可以在任何正常编译的程序中使用,包括作为完整的系统程序,甚至作为其他脚本的解释器 。 尽管如此,一些早期版本的内核支持将解释器指令的长度限制为大约32个字符(在第一次执行时只有16个字符),不能将解释器名称与指令中的任何参数分开,或者具有其他的怪癖。 此外,一些现代系统允许为了安全目的而限制或禁用整个机制(例如,许多系统上的脚本已禁用set-user-id支持)。 – WP

  2. 而这个输出从COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39 COLUMNS=75 man execve | grep -nA 23 " Interpreter scripts" | head -39Ubuntu 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脚本是可移植的。 阅读手册页以获取更多详细信息,包括二进制可执行文件和脚本之间调用的其他差异。