快速回答
壳牌报价处理正在折叠和连接它认为只是一个论点的东西。您的调用相当于
$ perl '-ienext unless /g/i'
它立即中止,因为 perl 将此参数解析为包含-u
,这会触发核心转储,您的代码将开始执行。这是一个曾经用于创建伪可执行文件的旧功能,但如今它在本质上已经退化了。
似乎eval
是对-e 'ss /g/i'
.
第一条线索
B::Deparse可以你的朋友,只要你碰巧在没有dump
支持的系统上运行。
$ echo 1 | perl -MO=Deparse,-p -ie'next unless /g/i'
dump is not supported.
BEGIN { $^I = "enext"; }
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined(($_ = <ARGV>))) {
chomp($_);
(('ss' / 'g') / 'i');
}
那么为什么会unle
消失呢?如果您正在运行 Linux,那么您可能还没有达到我的水平。上面的输出来自 Cygwin 上的 Perl,关于dump
不受支持的错误是一个线索。
下一条线索
perlrun 文档中的注意事项:
-u
此开关会导致 Perl 在编译程序后转储内核。然后,理论上您可以使用undump程序(未提供)将此核心转储并转换为可执行文件。这会以牺牲一些磁盘空间为代价来加快启动速度(您可以通过剥离可执行文件来最小化)。(不过,“hello world”可执行文件在我的机器上大约有 200K。)如果您想在转储之前执行程序的一部分,请改用dump
运算符。注意:undump的可用性是平台特定的,可能不适用于特定的 Perl 端口。
工作假设和确认
Perl 的参数处理将整个块视为单个选项集群,因为它以破折号开头。该-i
选项使用下一个单词 ( enext
),正如我们在处理的实现中-i
看到的那样。
case 'i':
Safefree(PL_inplace);
[Cygwin-specific code elided -geb]
{
const char * const start = ++s;
while (*s && !isSPACE(*s))
++s;
PL_inplace = savepvn(start, s - start);
}
if (*s) {
++s;
if (*s == '-') /* Additional switches on #! line. */
s++;
}
return s;
对于备份文件的扩展名,上面来自perl.c的代码最多使用第一个空白字符或字符串结尾,以先到者为准。如果还有字符,第一个必须是空格,然后跳过它,如果下一个是破折号,那么也跳过它。在 Perl 中,您可以将此逻辑写为
if ($$s =~ s/i(\S+)(?:\s-)//) {
my $extension = $1;
return $extension;
}
然后,所有-u
, -n
, -l
, 和-e
都是有效的 Perl 选项,因此参数处理会吃掉它们并留下无意义的
ss /g/i
作为 的参数-e
,perl 将其解析为一系列除法。但在执行甚至可以开始之前,古老的-u
导致 perl 转储核心。
意外行为
更奇怪的是,如果你在next
和之间放置两个空格unless
$ perl -ie'next unless /g/i'
程序尝试运行。回到我们看到的主选项处理循环
case '*':
case ' ':
while( *s == ' ' )
++s;
if (s[0] == '-') /* Additional switches on #! line. */
return s+1;
break;
额外的空格会终止对该参数的选项解析。见证:
$ perl -ie'next 废话 -garbage --foo' -e die
死于 -e 第 1 行。
但没有我们看到的额外空间
$ perl -ie'next 废话 -garbage --foo' -e die
无法识别的开关:-onsense -garbage --foo(-h 将显示有效选项)。
然而,有了额外的空格和破折号,
$ perl -ie'next -除非 /g/i'
不支持转储。
设计动机
正如评论所表明的那样,为了严格的 shebang( #!
) 行约束而存在逻辑,perl 会尽力解决这个问题。
解释器脚本
解释器脚本是一个启用了执行权限的文本文件,其第一行的格式为:
#! interpreter [optional-arg]
解释器必须是本身不是脚本的可执行文件的有效路径名。如果 filename 参数execve
指定了解释器脚本,则解释器将使用以下参数调用:
interpreter [optional-arg] filename arg...
其中arg...argv
是 的论点所指向的一系列词execve
。
对于便携使用,optional-arg应该不存在,或者指定为单个单词(即,它不应包含空格)......</p>