Perl如何避免shebang循环?

Gre*_*bet 10 perl

perl解释了shebang本身并模仿了它的行为exec*(2).我认为它模仿了Linux在所有空白上分裂的行为,而不是BSD第一个只有空白的东西,但是没关系.

就像快速演示一样 really_python.pl

#!/usr/bin/env python

# the following line is correct Python but not correct Perl
from collections import namedtuple
print "hi"
Run Code Online (Sandbox Code Playgroud)

调用时打印为hi perl really_python.pl.

此外,下面的程序将做正确的事情,而不管它们是否被援引为perl program或./program.

#!/usr/bin/perl
print "hi\n";
Run Code Online (Sandbox Code Playgroud)

和

#!/usr/bin/env perl
print "hi\n";
Run Code Online (Sandbox Code Playgroud)

我不明白为什么程序不是无限循环.在上述任何一种情况下,shebang线都是或解析为perl解释器的绝对路径.似乎接下来应该发生的事情是perl解析文件,注意到shebang,并委托shebang路径(在这种情况下本身).是否perl比较家当路径自身的ARGV[0]?不perl看家当字符串,看看它是否包含"perl"一个子?

我试图使用符号链接来触发我期待的无限循环行为.

$ ln -s /usr/bin/perl /tmp/p

#!/tmp/p
print "hi\n";
Run Code Online (Sandbox Code Playgroud)

但该程序打印"hi",无论它是如何被调用的.

然而,在OS X上,我能够perl使用脚本欺骗无限的shebang循环.

的内容 /tmp/pscript

#!/bin/sh
perl "$@"
Run Code Online (Sandbox Code Playgroud)

perl脚本的内容

#!/tmp/pscript
print "hi\n";
Run Code Online (Sandbox Code Playgroud)

这确实是无限循环(在OS X上,尚未在Linux上测试过).

perl在合理的情况下正确处理shebangs显然会遇到很多麻烦.它不会被符号链接混淆,也不会被普通的env东西搞糊涂.到底是做什么的?

ike*_*ami 12

perlrun中提供了此功能的文档.

如果该#!行不包含单词"perl"或单词"indir",#!则执行以该命名的程序而不是Perl解释器.这有点奇怪,但它可以帮助那些不能做的人#!,因为他们可以告诉程序他们的SHELL是/ usr/bin/perl,然后Perl会将程序分派给正确的解释器.

因此,如果shebang包含perl或者indir,则来自shebang行的解释器不会被执行.

另外,如果argv[0]不包含shebang行的解释器,则不执行perl.这是阻止示例中的无限循环的原因.

  • 使用时启动perl /tmp/pscript,

    1. 内核执行perl /tmp/pscript,
    2. 然后perl执行/tmp/p /tmp/pscript.
    3. 此时,argv[0]不包含perl,所以shebang线不再相关.
  • 使用时启动/tmp/pscript,

    1. 内核执行/tmp/p /tmp/pscript.
    2. 此时,argv[0]不包含perl,所以shebang线不再相关.


Thi*_*Not 12

相关代码在toke.c中,Perl词法分析器.如果:

  • 第1行以#!(可选地前面有空格)AND 开头

  • 不包含perl -AND

  • 不包含perl(除非后跟a 6,即perl6)AND

  • (在"DOSish"平台上)不包含perl(例如Perl)AND的不区分大小写的匹配

  • 不包含indirAND

  • 该-c标志未设置在命令行上和

  • argv[0] 包含 perl

shebang之后执行的程序execv.否则,词法分析器就会继续; perl本身并不exec存在.

因此,你可以使用shebang做一些非常奇怪的事情而不用perl尝试exec另一个解释器:

    #!     perl
#!foo perl
#!fooperlbar -p
#!perl 6
#!PeRl          # on Windows
Run Code Online (Sandbox Code Playgroud)

您的符号链接示例符合上面列出的所有条件,那么为什么没有无限循环?你可以看到发生了什么strace:

$ ln -s /usr/bin/perl foo
$ echo '#!foo' > bar
$ strace perl bar 2>&1 | grep exec
execve("/bin/perl", ["perl", "bar"], [/* 27 vars */]) = 0
execve("foo", ["foo", "bar"], [/* 27 vars */]) = 0
Run Code Online (Sandbox Code Playgroud)

Perl实际上做exec了链接,但因为它不包含perl在名称中,所以第二次不再满足最后一个条件并且循环结束.