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";