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;
确实狡猾......有人可以详细解释这是如何运作的吗?
答案 0 :(得分:27)
这个想法是,如果在标准的Bourne shell(sh),C shell(csh)或Perl中评估它们,那么这三行会做3种不同的事情。只有在脚本开头不支持使用#!
行指定解释器名称的系统上才需要此hack。如果以这3行作为shell脚本执行Perl脚本,shell将启动Perl解释器,并向其传递脚本的文件名和命令行参数。
在Perl中,三行形成一个语句,以;
结尾,形式为
eval '...' && eval '...' & eval '...' if $running_under_some_shell;
由于脚本刚刚启动,$running_under_some_shell
为undef
,这是假的,并且永远不会执行。这是一个无操作。
狡猾的部分是,$?0
在sh与csh中的解析方式不同。在sh中,这意味着$?
(最后一个命令的退出状态)后跟0.由于没有上一个命令,$?
将为0,因此$?0
计算为{{1 }}。在csh中,00
是一个特殊变量,如果当前输入文件名已知,则为1,否则为0。由于shell正在从脚本中读取这些行,$?0
将为1。
因此,在sh中,$?0
表示eval '(exit $?0)'
,而在csh中表示eval '(exit 00)'
。 parens表示应该在子shell中评估exit命令。
sh和csh都将eval '(exit 1)'
理解为“执行上一个命令,然后仅在前一个命令退出0时才执行以下命令”。所以只有sh才会执行&&
。 csh将进入下一行。
csh会在行的开头忽略“&”。 (我不确定这对csh意味着什么。它的目的是从Perl的角度来看这个表达式。)然后csh继续评估eval 'exec perl -wS $0 ${1+"$@"}'
。
这两个命令行非常相似。 eval 'exec /usr/bin/perl -wS $0 $argv:q'
表示通过启动exec perl
的副本来替换当前流程。 perl
表示与-wS
(启用警告)和-w
相同(在-S
中查找指定的脚本)。 $PATH
是脚本的文件名。最后,$0
和${1+"$@"}
都生成当前命令行参数的副本(分别在sh和csh中)。
它使用$argv:q
代替更常见的${1+"$@"}
来解决某些古老版Bourne shell中的错误。他们的意思是一样的。您可以在Bennett Todd's explanation中阅读详细信息(复制在gbacon的答案中)。
答案 1 :(得分:10)
来自Tom Christiansen的收藏Far More Than Everything You've Ever Wanted to Know About …:
eval 'exec perl $0 -S ${1+"$@"}'
新闻组:comp.lang.tcl,comp.unix.shell
来自:bet@ritz.mordor.com(Bennett Todd)
主题:回复:"$@"
与${1+"$@"}
Followup-To:comp.unix.shell
日期:1995年9月26日星期二,格林威治标准时间14:35:45 消息ID:< DFIoJL.934@ritz.mordor.com>(这不是一个真正的TCL问题;它是一个Bourne Shell问题;所以我已经 交叉发布,并设置后续,到comp.unix.shell)。
曾几何时(故事情节如此),某处有一个Bourne Shell 它为插入整个命令行提供了两种选择。该 最简单的是
$*
,它只是在所有的args中被包围,失去了任何引用 保护了内部空白。它还提供"$@"
来保护 空白。现在icko位是"$@"
的实现方式。在这早期 shell,双字符序列$@
将插入为$1" "$2" "$3" "$4" ... $n
这样当你添加周围的引号时,就完成了整个引用 schmeer。可爱,可爱,太可爱......现在考虑一下正确的用法
如果没有args ,"$@"
将扩展为:
""
这是空字符串 - 长度为零的单个参数。那是不是 就像没有args一样。所以,有人提出了一个聪明的应用程序 另一个Bourne Shell功能,条件插值。成语
如果设置了${varname+value}
value
,则扩展为
varname
,否则不会扩展为${1+"$@"}
。就这样 正在讨论的成语"$@"
与完整的
完全相同{{1}}没有那个古老的,非常奇怪的错误。所以现在问题是:有哪些那个bug?有没有贝壳 包含它的任何甚至是含糊不清的最新操作系统都附带了吗?
-- -Bennett bet@mordor.com http://www.mordor.com/bet/