代码之家  ›  专栏  ›  技术社区  ›  JoelFan

解释Perl“序言”的不确定性

  •  14
  • JoelFan  · 技术社区  · 14 年前

    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;
    

    真的很狡猾…有人能详细解释一下这是怎么工作的吗?

    2 回复  |  直到 10 年前
        1
  •  27
  •   cjm    14 年前

    其思想是,如果在标准BourneShell(sh)、C shell(c sh)或Perl中对这三行进行评估,那么这三行执行三种不同的操作。只有在不支持使用 #! 脚本开头的行。如果以这三行开头的Perl脚本作为shell脚本执行,shell将启动Perl解释器,并将脚本的文件名和命令行参数传递给它。

    在Perl中,三行构成一个语句,以 ; ,形式

    eval '...' && eval '...' & eval '...' if $running_under_some_shell;
    

    自从剧本刚开始, $running_under_some_shell undef ,这是错误的,evals永远不会被执行。这是一个NOP。

    最诡异的是 $?0 在sh和csh中的解析方式不同。在上海,这意味着 $? (最后一个命令的退出状态)后跟0。因为之前没有命令, $? 将是0,所以 $?零 评估为 00 . 在CSH中, $?零 是一个特殊变量,如果当前输入文件名已知,则为1,否则为0。因为shell正在从脚本中读取这些行, $?零 将是1。

    因此,在sh中, eval '(exit $?0)' 方法 eval '(exit 00)' 在CSH中,这意味着 eval '(exit 1)' . parens表示exit命令应该在子shell中进行计算。

    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 +“$@”} 而不是更平常 "$@" 在一些古代版本的伯恩贝壳中研究一只虫子。他们的意思是一样的。您可以在 Bennett Todd's explanation (复制在GBACON的答案中)。

        2
  •  10
  •   Greg Bacon    14 年前

    来自汤姆·克里斯蒂安的收藏 Far More Than Everything You've Ever Wanted to Know About … :

    Why we use eval 'exec perl $0 -S ${1+"$@"}'

    新闻组:comp.lang.tcl,comp.unix.shell
    发件人:bet@ritz.mordor.com(bennett todd)
    主题:Re: "$@" 对战 ${1+"$@"}
    继续:comp.unix.shell
    日期:1995年9月26日星期二14:35:45格林尼治标准时间
    消息ID:<dfiojl.934@ritz.mordor.com>

    (这不是一个真正的TCL问题;这是一个Bourne-Shell问题;所以我 交叉发布,并设置后续,到comp.unix.shell)。

    从前(或者说故事是这样说的),在某个地方有一个弹簧壳 这为插入整个命令行提供了两种选择。这个 最简单的是 $* 它刚刚借了所有的参数,失去了任何引用 保护了内部空白。它还提供 “$@” 为了保护 空白。现在,爱可比特是如何 “$@” 已实现。在这个早期 shell,两个字符的序列 $@ 将插入为

    $1" "$2" "$3" "$4" ... $n
    

    这样,当您添加周围的引号时,它就完成了整个引用 施密尔。可爱,可爱,太可爱了…现在考虑什么是正确的用法

    "$@"
    

    将扩展到 如果没有参数 :

    ""
    

    这是空字符串,长度为零的单个参数。那是 和完全没有参数一样。所以,有人想出了一个聪明的应用程序 另一个Bourne shell特性,条件插值。成语

    ${varname+value}
    

    扩展到 value 如果 varname 已设置,但没有其他设置。因此 讨论中的成语

    ${1+"$@"}
    

    意思与简单的

    “$@”
    

    没有那只古老的,非常奇怪的虫子。

    现在的问题是:什么炮弹 那个虫子?有贝壳吗 是否附带了包括它的任何甚至是模糊的最新操作系统?

    -- 
    -Bennett
    bet@mordor.com
    http://www.mordor.com/bet/