Perl手册描述了一个完全不同的构造,它可以在任何csh,sh或Perl下工作,如下所示:
eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
    & eval 'exec /usr/bin/perl -wS $0 $argv:q'
    if $running_under_some_shell;
Run Code Online (Sandbox Code Playgroud)
确实狡猾......有人可以详细解释一下这是如何运作的吗?
cjm*_*cjm 27
我们的想法是,如果在标准的Bourne shell(sh),C shell(csh)或Perl中进行评估,这三行会做3种不同的事情.只有在不支持使用#!脚本开头的行指定解释器名称的系统上才需要此hack .如果以这3行作为shell脚本执行Perl脚本,shell将启动Perl解释器,并向其传递脚本的文件名和命令行参数.
在Perl中,三条线形成一个语句,由终止;,表单的
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
Run Code Online (Sandbox Code Playgroud)
由于脚本刚刚启动,$running_under_some_shell是undef,这是错误的,并且永远不会执行.这是一个无操作.
狡猾的部分$?0在sh与csh中的解析方式不同.在sh中,这意味着$?(最后一个命令的退出状态)后跟0.由于没有上一个命令,因此$?将为0,因此$?0求值为00.在csh中,$?0是一个特殊变量,如果当前输入文件名已知,则为1,否则为0.由于shell从脚本中读取这些行,因此$?0将为1.
因此,在sh,eval '(exit $?0)'means eval '(exit 00)'和csh中它意味着eval '(exit 1)'.parens表示应该在子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的答案中).
Gre*_*con 10
从汤姆克里斯蒂安森的收藏品远远超过你曾经想知道的一切......:
eval 'exec perl $0 -S ${1+"$@"}'新闻组:comp.lang.tcl,comp.unix.shell
来自:bet@ritz.mordor.com(Bennett Todd)
主题:Re:"$@"与${1+"$@"}
Followup-To:comp.unix.shell
日期:星期二,1995年9月26日14:35 :45 GMT
消息ID:<DFIoJL.934@ritz.mordor.com>(这不是一个真正的TCL问题;它是一个Bourne Shell问题;所以我已经交叉发布并设置后续内容到comp.unix.shell).
曾几何时(故事情节如此),某处有一个Bourne Shell,它为插入整个命令行提供了两种选择.最简单的是
$*,只是在所有的args中被包围,失去了任何保护内部空白的引用.它还提供"$@",以保护空白.现在icko位是如何"$@"实现的.在这个早期的shell中,双字符序列$@将插值为Run Code Online (Sandbox Code Playgroud)$1" "$2" "$3" "$4" ... $n所以当你添加周围的引号时,它就完整地引用了整个schmeer.可爱,可爱,太可爱......现在考虑一下正确的用法
Run Code Online (Sandbox Code Playgroud)"$@"如果没有args,将扩展为:
Run Code Online (Sandbox Code Playgroud)""这是空字符串 - 长度为零的单个参数.这 与根本没有args 是不一样的.因此,有人想出了另一个Bourne Shell功能的条件插值的巧妙应用.成语
Run Code Online (Sandbox Code Playgroud)${varname+value}扩展为
valueifvarname设置,否则没有.因此,正在讨论的成语Run Code Online (Sandbox Code Playgroud)${1+"$@"}意思是指与一个简单的完全相同
Run Code Online (Sandbox Code Playgroud)"$@"没有那个古老,极其奇怪的虫子.
那么现在的问题是:那个虫有什么炮弹?是否包含任何包含它的最近操作系统附带的任何外壳?
-- -Bennett bet@mordor.com http://www.mordor.com/bet/