我可以使用可变内容作为 shebang 吗?

我可以使用可变内容作为 shebang 吗?

我有一个 shell 脚本,我想在其中添加一个 shebang。给定一个定义如下的变量:

SHEBANG="#!/bin/sh"

我的问题是我是否可以在另一个脚本中使用该变量,如下所示:

$SHEBANG
# other stuff...

答案1

不会。shebang 行由您的内核或系统库* 处理,并且不处理 shell 变量。

  • 如果您出于某种原因想使用环境变量作为解释器,您可以创建一个重新生成的“trampoline”可执行文件(不是脚本!)$SHEBANG "$@"。在这种情况下,您需要省略#!变量中的 ;#!仅当它实际上是文件的前两个字节时才有用。

  • 另一种选择是利用事实上,没有 shebang 行的脚本(通常)将作为 shell 脚本与sh调用 shell一起执行。如果您的 shebang 目标有一个与 shell 语法有效重叠的注释语法,您就可以使其工作。这种策略在 Lisp 解释器中很常见,或者曾经很常见。在您的示例中,解释器也是sh,这是不可行的。

  • 如果您可以依赖在场,您可以在该行上进一步推进bash:第一行是的脚本

    exec /bin/bash -c 'exec "$SHEBANG" <(tail -n +2 "$0")' "$0" "$@"
    

    适用于大多数口译员; Bash 用作中间步骤,以便流程替代可以用来拥有tail为我们跳过第一行,这样我们就不会陷入无限循环。一些解释器要求文件是可查找的,并且他们不会接受这样的管道。


值得考虑的是这是否真的是您想做的事情。除了任何安全问题之外,它并不是很有用:很少有脚本可以像这样改变其解释器,并且在可以的情况下,您几乎肯定会使用更受限制的逻辑块来更好地生成适合情况的正确逻辑块(可能是介于两者之间的 shell 脚本,它以实际脚本的路径作为参数来调用解释器)。


* 不总是;在某些情况下,某些 shell 会自行读取它,但它们仍然不会进行变量扩展。

答案2

我不知道这是否是您想要的用例,但是您有一件事做的是

#!/usr/bin/env python

所以你的脚本使用第一个pythonin而$PATH不是需要硬编码/usr/bin/python,这可能在某些包含“好”版本的 python 的系统上运行良好。/usr/local/bin/opt

为什么使用“#!/usr/bin/env NAME”而不是“#!/path/to/NAME”作为我的 shebang 更好?


这不会创建无限循环,因为 Python 解释器(env在文件上调用)只是将该#!行视为注释。这是设计的重点#!,因为许多语言都使用#注释字符。

为了扩展这一点,你可以编写一个多语言程序它最初在 下运行#!/bin/sh,但随后找出实际使用的解释器,并在同一脚本上调用它。

原来已经有具有多行 shebang 技巧的网页对于许多语言,包括编译语言(脚本将其自身的一部分提供给编译器并运行输出)。


手册perlrun页给出了这个示例作为替代#!/usr/bin/env perl

    #!/bin/sh
    #! -*-perl-*-
    eval 'exec perl -x -wS $0 ${1+"$@"}'
        if 0;

    your perl script goes here

当作为/bin/sh脚本运行时,在您的脚本上eval运行perl -x -wS,并传递您的参数。

当 Perl 运行它时,由下一行eval的 控制,因此它永远不会运行。if 0;与 不同sh,Perl 语句不以换行符结束。

"$SHEBANG"您可以使用代替perl,甚至运行多个sh命令来选择要使用的 perl 解释器,从而使其变得更复杂。

答案3

我想这就是你想要的:

xb@dnxb:/tmp$ cat /tmp/hole.sh
#!/usr/bin/$shell_var
echo 1
readlink "/proc/$$/exe"
echo 2
function f { echo hello world; } 
echo 3 
xb@dnxb:/tmp$ chmod +x /tmp/hole.sh
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/dash -- "$@"
xb@dnxb:/tmp$ sudo chmod +x /usr/bin/\$shell_var
xb@dnxb:/tmp$ ./hole.sh
1
/bin/dash
2
./hole.sh: 5: ./hole.sh: function: not found
3
xb@dnxb:/tmp$ sudo vi /usr/bin/\$shell_var 
xb@dnxb:/tmp$ cat /usr/bin/\$shell_var 
#!/bin/bash
/bin/bash -- "$@"
xb@dnxb:/tmp$ ./hole.sh 
1
/bin/bash
2
3
xb@dnxb:/tmp$ 

解释:

  1. 使用\$shell_varfile 作为“变量”来定义您想要的 shell。

  2. readlink "/proc/$$/exe"将打印当前外壳

  3. 由于破折号不支持function f { echo hello world; }句法,所以它产生了错误function: not found,但是将文件中的 shell 更改为 bash\$shell_var将不会再出现错误。

  4. 完整的文件路径(或相对路径,如果 ./hole.sh 在 /tmp 中运行)将传递给$@\$shell_var文件,/tmp/hole.sh并将在\$shell_var.

相关内容