解释 Perl “序言"的狡猾之处 [英] Explain the deviousness of the Perl "preamble"

查看:24
本文介绍了解释 Perl “序言"的狡猾之处的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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_shellundef,这是错误的,并且永远不会执行 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆