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,
perl /tmp/pscript,perl执行/tmp/p /tmp/pscript.argv[0]不包含perl,所以shebang线不再相关.使用时启动/tmp/pscript,
/tmp/p /tmp/pscript.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在名称中,所以第二次不再满足最后一个条件并且循环结束.