Perl如何避免shebang循环?

Perl如何避免shebang循环?,perl,Perl,perl解释shebang本身并模仿exec*(2)的行为。我认为它模拟了Linux在所有空格上进行分割的行为,而不是BSD第一个空格唯一的东西,但没关系 作为一个快速演示真的\u python.pl #!/usr/bin/env python # the following line is correct Python but not correct Perl from collections import namedtuple print "hi" 当调用为perl really\u p

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

作为一个快速演示
真的\u python.pl

#!/usr/bin/env python

# the following line is correct Python but not correct Perl
from collections import namedtuple
print "hi"
当调用为
perl really\u python.pl
时打印hi

此外,无论以下程序是作为
perl程序
还是
/program
调用,它们都将做正确的事情

#!/usr/bin/perl
print "hi\n";

我不明白为什么程序不是无限循环。在上述任何一种情况下,shebang行都是或解析为
perl
解释器的绝对路径。似乎接下来应该发生的事情是
perl
解析文件,注意shebang,并委托给shebang路径(在本例中为自身)。
perl
是否将shebang路径与其自身的
ARGV[0]
进行比较?
perl
是否查看shebang字符串并查看它是否包含作为子字符串的
“perl”

我试图使用一个符号链接来触发我所期望的无限循环行为

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

#!/tmp/p
print "hi\n";
但无论如何调用,该程序都会打印“hi”

然而,在OSX上,我能够用一个脚本将
perl
欺骗成一个无限的shebang循环

/tmp/pscript的内容

#!/bin/sh
perl "$@"
perl脚本的内容

#!/tmp/pscript
print "hi\n";
这是无限循环(在OSX上,还没有在Linux上测试)


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

此功能的文档可在中找到

如果
#行既不包含单词“perl”也不包含单词“indir”,即以
命名的程序而不是Perl解释器。这有点奇怪,但它可以帮助那些不执行
#的机器上的人,因为它们可以告诉程序它们的SHELL是/usr/bin/perl,然后perl会为它们将程序分派到正确的解释器

因此,如果shebang包含
perl
indir
,则不会执行shebang行中的解释器

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

  • 使用
    perl/tmp/pscript
    启动时

  • 内核执行
    perl/tmp/pscript
  • 然后
    perl
    执行
    /tmp/p/tmp/pscript
  • 此时,
    argv[0]
    不包含
    perl
    ,因此shebang行不再相关
  • 使用
    /tmp/pscript
    启动时

  • 内核执行
    /tmp/p/tmp/pscript
  • 此时,
    argv[0]
    不包含
    perl
    ,因此shebang行不再相关
相关代码在Perl lexer中。如果:

  • 第1行以
    #开头(可选前面加空格)和

  • 不包含
    perl-

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

  • (在“DOSSH”平台上)不包含
    perl
    (例如
    perl
    )和

  • 不包含
    indir

  • 未在命令行上设置
    -c
    标志,并且

  • argv[0]
    包含
    perl

使用
execv
执行shebang之后的程序。否则,lexer将继续运行;perl本身不执行
exec

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

#!perl
#!foo-perl
#!fooperlbar-p
#!perl 6
#!Windows上的PeRl

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

$ln-s/usr/bin/perl-foo
$echo'#!酒吧
$strace perl bar 2>&1| grep exec
execve(“/bin/perl”、[“perl”、“bar”]、[/*27 vars*/])=0
execve(“foo”,“foo”,“bar”],[/*27变量*/])=0

Perl实际上确实执行了链接,但因为它的名称中不包含Perl,最后一个条件在第二次循环中不再满足,循环结束。

而且,从5.24开始,“perl6”一词被认为与“Perl”不匹配,这意味着如果perl5解释器运行带有perl6 shebang的程序,它将在perl6重新执行,而不是尝试自己运行它
perlrun
似乎没有更新以反映这一点。(如果你真的决定得到一个循环,你可能可以通过将Perl5.24符号链接为
perl6
,因为循环中断条件没有这个例外。)@hobbs,我链接到的代码是针对5.24的。进一步的细节可以在那里看到,在这本书里是布莱克诺的答案。我将答案限制在问题的范围内,但确实存在其他“隐藏”规则。注意:这假设OP使用
perl/tmp/pscript
启动脚本。使用
/tmp/pscript
启动脚本时,答案略有不同。
#!/tmp/pscript
print "hi\n";