Relative shebang: How to write an executable script 运行 自带的可移植解释器

Relative shebang: How to write an executable script running portable interpreter which comes with it

假设我们有一个 program/package,它带有自己的解释器和一组应该在执行时调用它的脚本(使用 shebang)。

假设我们希望保持它的可移植性,因此即使只是简单地复制到不同的位置(不同的机器)而不调用 setup/install 或修改环境 (PATH),它仍然可以运行。这些脚本不应混入系统解释器。

给定的约束排除了两种已知的方法,例如带绝对路径的 shebang:

#!/usr/bin/python 

并在环境中搜索

#!/usr/bin/env python

单独的发射器看起来很丑,不能接受。

我发现了 shebang 限制的一个很好的总结,它描述了为什么 shebang 中的相对路径是无用的,并且不能有一个以上的参数给解释器:http://www.in-ulm.de/~mascheck/various/shebang/

而且我还发现 practical solutions 大多数语言都有 'multi-line shebang' 技巧。它允许编写这样的脚本:

#!/bin/sh
"exec" "`dirname [=13=]`/python2.7" "[=13=]" "$@"
print copyright

但有时,我们不希望 extend/patch 依赖于 shebang 的现有脚本使用此方法向解释器提供绝对路径。例如。 Python 的 setup.py 支持 --executable 选项,它基本上允许为其生成的脚本指定 shebang 内容:

python setup.py build --executable=/opt/local/bin/python

那么,特别是,可以为 --executable= 指定什么以实现所需的可移植性?或者换句话说,因为我不想让问题过于具体 Python...

问题

如何编写一个 shebang,它指定一个解释器,其路径与正在执行的脚本的位置相关?

直接写在 shebang 中的相对路径是相对于当前工作目录的,所以像 #!../bin/python2.7 这样的东西对除少数以外的任何其他工作目录都不起作用。

既然OS不支持,为什么不使用外部程序,如使用env进行PATH查找。但我知道没有专门的程序可以根据参数计算相对路径并执行结果命令.. 除了 shell 本身和其他脚本引擎。

但是尝试在 shell 脚本中计算路径,例如

#!/bin/sh -c '`dirname [=10=]`/python2.7 [=10=]'

不起作用,因为在 Linux shebang 仅受一个参数的限制。这建议我寻找接受脚本作为命令行第一个参数并能够执行新进程的脚本引擎:

使用 AWK

#!/usr/bin/awk BEGIN{a=ARGV[1];sub(/[a-z_.]+$/,"python2.7",a);system(a"\t"ARGV[1])}

使用 Perl

#!/usr/bin/perl -e$_=$ARGV[0];exec(s/\w+$/python2.7/r,$_)

21 年 1 月 11 日更新:

使用更新的 env 实用程序:

$ env --version | grep env
env (GNU coreutils) 8.30
$ env --help
Usage: env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]
Set each NAME to VALUE in the environment and run COMMAND.

Mandatory arguments to long options are mandatory for short options too.
  -i, --ignore-environment  start with an empty environment
  -0, --null           end each output line with NUL, not newline
  -u, --unset=NAME     remove variable from the environment
  -C, --chdir=DIR      change working directory to DIR
  -S, --split-string=S  process and split S into separate arguments;
                        used to pass multiple arguments on shebang lines

因此,将 -S 传递给 env 即可完成工作