我知道这是不正确的。我只是想知道perl如何解析它。
所以,我正在玩perl,我想要的是perl -ne
我输入的是perl -ie
这种行为很有趣,我想知道发生了什么。
$ echo 1 | perl -ie'next unless /g/i'
那就是perl Aborted (core dumped)
。阅读perl --help
我看到-i
需要扩展备份。
-i[extension] edit <> files in place (makes backup if extension supplied)
对于那些不知道-e
只是eval的人。所以我认为在解析为
perl -i -e'next unless /g/i'
我得到了undef,剩下的就是e 的论据perl -ie 'next unless /g/i'
我得到了参数e,其余的就像文件名一样悬挂 perl -i"-e'next unless /g/i'"
整个事情作为我 当我跑步时
$ echo 1 | perl -i -e'next unless /g/i'
该程序不会中止。这使我相信'next unless /g/i'
没有被解析为-e
的文字参数。明确地说,上面的内容将以这种方式进行解析,结果会有所不同。
那是什么?好好玩一点,我得到了
$ echo 1 | perl -ie'foo bar'
Unrecognized switch: -bar (-h will show valid options).
$ echo 1 | perl -ie'foo w w w'
... works fine guess it reads it as `perl -ie'foo' -w -w -w`
玩弄上述内容,我试试这个......
$ echo 1 | perl -ie'foo e eval q[warn "bar"]'
bar at (eval 1) line 1.
现在我真的很困惑。那么Perl如何解析这个呢?最后,您似乎可以从-i
内获得Perl eval命令。这有安全隐患吗?
$ perl -i'foo e eval "warn q[bar]" '
答案 0 :(得分:7)
Shell报价处理正在崩溃并连接它认为是一个参数的内容。您的调用等同于
$ 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
的错误是一个线索。
<强>
-u
强>此开关导致Perl在编译程序后转储核心。然后,理论上可以使用 undump 程序(未提供)将此核心转储转换为可执行文件。这会以某些磁盘空间为代价加速启动(您可以通过剥离可执行文件来最小化)。 (仍然,我的机器上的“hello world”可执行文件大约200K。)如果要在转储之前执行程序的一部分,请改用
dump
运算符。注意: undump 的可用性是特定于平台的,可能不适用于Perl的特定端口。
Perl的参数处理将整个块视为一个选项集群,因为它以破折号开头。我们可以在implementation for -i
processing中看到-i
选项使用下一个字(enext
)。
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'
程序试图运行。 Back in the main option-processing loop我们看到了
case '*':
case ' ':
while( *s == ' ' )
++s;
if (s[0] == '-') /* Additional switches on #! line. */
return s+1;
break;
额外空间终止对该参数进行解析的选项。证人:
$ perl -ie'next nonsense -garbage --foo' -e die Died at -e line 1.
但没有我们看到的额外空间
$ perl -ie'next nonsense -garbage --foo' -e die Unrecognized switch: -onsense -garbage --foo (-h will show valid options).
但是,如果有额外的空格和破折号,
$ perl -ie'next -unless /g/i' dump is not supported.
正如评论所指出的那样,逻辑就是harsh shebang (#!
) line constraints,perl会尽力解决这个问题。
解释器脚本
解释器脚本是一个文本文件,它启用了执行权限,其第一行的格式为:
#! interpreter [optional-arg]
解释器必须是可执行文件的有效路径名,而该可执行文件本身不是脚本。如果
execve
的filename参数指定了解释器脚本,则将使用以下参数调用解释器:interpreter [optional-arg] filename arg...
其中 arg ... 是
argv
的{{1}}参数指向的一系列单词。对于便携式使用, optional-arg 应该不存在,或者指定为单个单词(即,它不应包含空格)...
答案 1 :(得分:5)
要了解三件事:
'-x y'
表示-xy
为Perl(对于某些任意选项“x”和“y”)。
-xy
是代表-x -y
的“捆绑”。
-i
,就像-e
吸收其余的论点一样。与-e
不同,它将空格视为参数的结尾(按照上面的#1)。
这意味着
-ie'next unless /g/i'
这只是一种奇特的写作方式
'-ienext unless /g/i'
unbundles to
-ienext -u -n -l '-ess /g/i'
^^^^^ ^^^^^^^
---------- ----------
val for -i val for -e
perlrun个文件-u
为:
此开关导致Perl在编译程序后转储核心。然后,您可以理论上使用此核心转储并使用undump程序(未提供)将其转换为可执行文件。这会以某些磁盘空间为代价加速启动(您可以通过剥离可执行文件来最小化)。 (仍然,我的机器上的“hello world”可执行文件大约200K。)如果要在转储之前执行程序的一部分,请使用dump()运算符。注意:undump的可用性是特定于平台的,可能不适用于Perl的特定端口。