解释Perl的“序言"的曲解 [英] Explain the deviousness of the Perl "preamble"
问题描述
Perl手册描述了一个完全曲折的构造,该构造可在csh,sh或Perl中的任何一种下工作,例如以下
The Perl manual describes a totally devious construct that will work under any of csh, sh, or Perl, such as the following:
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
& eval 'exec /usr/bin/perl -wS $0 $argv:q'
if $running_under_some_shell;
确实不真实...有人可以详细解释它的工作原理吗?
Devious indeed... can someone please explain in detail how this works?
推荐答案
想法是,如果在标准的Bourne shell(sh),C shell(csh)或Perl.仅在不支持在脚本开头使用#!
行指定解释器名称的系统上,才需要使用此技巧.如果您以这3行开头的Perl脚本作为Shell脚本执行,则Shell将启动Perl解释器,并向其传递脚本的文件名和命令行参数.
The idea is that those three lines do 3 different things if they're evaluated in a standard Bourne shell (sh), a C shell (csh), or Perl. This hack is only needed on systems that don't support specifying an interpreter name using a #!
line at the start of a script. If you execute a Perl script beginning with those 3 lines as a shell script, the shell will launch the Perl interpreter, passing it the script's filename and the command line arguments.
在Perl中,三行形成一个语句,以;
终止,形式为
In Perl, the three lines form one statement, terminated by the ;
, of the form
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
由于脚本刚刚启动,所以$running_under_some_shell
是undef
,这是错误的,并且永远不会执行评估.这是无人操作.
Since the script just started, $running_under_some_shell
is undef
, which is false, and the evals are never executed. It's a no-op.
曲折的部分是$?0
在sh和csh中的解析方式有所不同.在sh中,这意味着$?
(最后一个命令的退出状态)后跟0.由于没有上一个命令,$?
将为0,因此$?0
的值为00
.在csh中,$?0
是一个特殊变量,如果知道当前输入的文件名,则为1,否则为0.由于外壳程序正在从脚本读取这些行,因此$?0
将为1.
The devious part is that $?0
is parsed differently in sh versus csh. In sh, that means $?
(the exit status of the last command) followed by 0. Since there is no previous command, $?
will be 0, so $?0
evaluates to 00
. In csh, $?0
is a special variable that is 1 if the current input filename is known, or 0 if it isn't. Since the shell is reading these lines from a script, $?0
will be 1.
因此,在sh中,eval '(exit $?0)'
表示eval '(exit 00)'
,在csh中表示eval '(exit 1)'
.括号表示应该在子外壳中评估exit命令.
Therefore, in sh, eval '(exit $?0)'
means eval '(exit 00)'
, and in csh it means eval '(exit 1)'
. The parens indicate that the exit command should be evaluated in a subshell.
sh和csh都将&&
理解为执行前一个命令,然后仅在前一个命令退出0时才执行以下命令".因此,只有sh会执行eval 'exec perl -wS $0 ${1+"$@"}'
. csh将进入下一行.
Both sh and csh understand &&
to mean "execute the previous command, then execute the following command only if the previous command exited 0". So only sh will execute eval 'exec perl -wS $0 ${1+"$@"}'
. csh will proceed to the next line.
csh将在一行的开头忽略&". (我不确定csh到底意味着什么.它的目的是从Perl的角度使它成为单个表达式.)然后csh继续计算eval 'exec /usr/bin/perl -wS $0 $argv:q'
.
csh will ignore "& " at the beginning of a line. (I'm not sure exactly what that means to csh. Its purpose is to make this a single expression from Perl's point of view.) csh then proceeds to evaluate eval 'exec /usr/bin/perl -wS $0 $argv:q'
.
这两个命令行非常相似. exec perl
表示通过启动perl
的副本来替换当前进程. -wS
的含义与-w
(启用警告)和-S
(在$PATH
中查找指定的脚本)相同. $0
是脚本的文件名.最后,${1+"$@"}
和$argv:q
都生成当前命令行参数的副本(分别在sh和csh中).
These two command lines are quite similar. exec perl
means to replace the current process by launching a copy of perl
. -wS
means the same as -w
(enable warnings) and -S
(look for the specified script in $PATH
). $0
is the filename of the script. Finally both ${1+"$@"}
and $argv:q
produce a copy of the current command line arguments (in sh and csh, respectively).
它使用${1+"$@"}
而不是更常见的"$@"
来解决某些古老版本的Bourne shell中的错误.他们是同一回事.您可以在贝内特·托德(Bennett Todd)的解释(复制于gbacon的答案)中阅读详细信息.
It uses ${1+"$@"}
instead of the more usual "$@"
to work around a bug in some ancient version of the Bourne shell. They mean the same thing. You can read the details in Bennett Todd's explanation (copied in gbacon's answer).
这篇关于解释Perl的“序言"的曲解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!