解释 Perl “序言"的狡猾之处 [英] Explain the deviousness of the Perl "preamble"
问题描述
Perl 手册描述了一个完全曲折的结构,可以在 csh、sh 或 Perl 中的任何一个下工作,例如以下:
eval '(exit $?0)' &&eval 'exec perl -wS $0 ${1+"$@"}'&eval 'exec/usr/bin/perl -wS $0 $argv:q'如果 $running_under_some_shell;
确实很狡猾……有人可以详细解释一下这是如何工作的吗?
这个想法是,如果这三行在标准 Bourne shell (sh)、C shell (csh) 或珀尔.仅在不支持在脚本开头使用 #!
行指定解释器名称的系统上才需要此 hack.如果您执行以这 3 行开头的 Perl 脚本作为 shell 脚本,shell 将启动 Perl 解释器,将脚本的文件名和命令行参数传递给它.
在 Perl 中,三行构成一个语句,以 ;
结尾,形式为
eval '...' &&评估'...' &eval '...' 如果 $running_under_some_shell;
由于脚本刚刚启动,$running_under_some_shell
是 undef
,这是错误的,并且永远不会执行 eval.这是一个空操作.
前面的部分是 $?0
在 sh 和 csh 中的解析方式不同.在sh中,这意味着$?
(最后一条命令的退出状态)后跟0.由于没有上一条命令,$?
将为0,所以$?0
计算结果为 00
.在 csh 中,$?0
是一个特殊变量,如果当前输入文件名已知,则为 1,否则为 0.由于 shell 从脚本中读取这些行,$?0
将为 1.
因此,在 sh 中,eval '(exit $?0)'
的意思是 eval '(exit 00)'
,而在 csh 中,它的意思是 eval '(出口1)'
.括号表示应该在子 shell 中评估 exit 命令.
sh 和 csh 都理解 &&
的意思是执行上一个命令,然后仅当上一个命令退出 0 时才执行以下命令".所以只有 sh 会执行 eval 'exec perl -wS $0 ${1+"$@"}'
.csh 将进入下一行.
csh 将忽略行首的&".(我不确定这对 csh 到底意味着什么.从 Perl 的角度来看,它的目的是使它成为一个单一的表达式.)然后 csh 继续评估 eval 'exec/usr/bin/perl -wS $0 $argv:q'
.
这两个命令行非常相似.exec perl
表示通过启动perl
的副本来替换当前进程.-wS
与 -w
(启用警告)和 -S
(在 $PATH
中查找指定脚本)的含义相同代码>).$0
是脚本的文件名.最后,${1+"$@"}
和 $argv:q
生成当前命令行参数的副本(分别在 sh 和 csh 中).>
它使用 ${1+"$@"}
而不是更常见的 "$@"
来解决一些古老版本的 Bourne shell 中的错误.他们的意思是一样的.您可以在 Bennett Todd 的解释(复制到 gbacon 的回答中)中阅读详细信息.
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?
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.
In Perl, the three lines form one statement, terminated by the ;
, of the form
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
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.
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.
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.
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 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'
.
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).
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屋!