免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3333 | 回复: 5
打印 上一主题 下一主题

#!/usr/bin/perl 的替换方案 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-07-02 15:33 |只看该作者 |倒序浏览
一下代码是功能同等于 #!/usr/bin/perl -w, 适用ksh, sh(这段代码摘自perldoc perlrun) 。 因为有些系统不能识别 #!.  请高手解释一下是如何工作的。 此断代码实际上是 以shell 代码运行的。 当作perl代码时直接就被忽略了(因为 if 0 这条语句)
                   eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
                    & eval 'exec /usr/bin/perl -wS $0 $argv:q'
                            if 0;

1. eval '(exit $?0)' 作用是什么?
2. 单个的 '&' 是做什么的,难道不是后台运行吗?
3. 为什么用  ${1+"$@"}, 而不直接用 "$@"?
4.  ‘if 0;’ 在shell 中语法是不对的,为什么运行在这里没问题呢?


perldoc 的原文:

            This example works on many platforms that have a shell compatible with Bourne shell:

                #!/usr/bin/perl
                eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}'
                        if $running_under_some_shell;

            The system ignores the first line and feeds the program to /bin/sh, which proceeds to
            try to execute the Perl program as a shell script.  The shell executes the second line
            as a normal shell command, and thus starts up the Perl interpreter.  On some systems $0
            doesn't always contain the full pathname, so the -S tells Perl to search for the program
            if necessary.  After Perl locates the program, it parses the lines and ignores them
            because the variable $running_under_some_shell is never true.  If the program will be
            interpreted by csh, you will need to replace "${1+"$@"}" with $*, even though that
            doesn't understand embedded spaces (and such) in the argument list.  To start up sh
            rather than csh, some systems may have to replace the "#!" line with a line containing
            just a colon, which will be politely ignored by Perl.  Other systems can't control that,
            and need 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;

论坛徽章:
0
2 [报告]
发表于 2012-07-02 23:19 |只看该作者
推荐你看一下perldoc -f eval

论坛徽章:
7
巳蛇
日期:2014-04-10 08:54:57白羊座
日期:2014-04-22 20:06:262015年亚洲杯之沙特阿拉伯
日期:2015-02-10 14:18:532015年辞旧岁徽章
日期:2015-03-03 16:54:152015亚冠之吉达阿赫利
日期:2015-06-02 11:34:112015亚冠之武里南联
日期:2015-06-24 12:13:082015亚冠之阿尔纳斯尔
日期:2015-08-03 09:08:25
3 [报告]
发表于 2012-07-03 13:49 |只看该作者
gangcai 发表于 2012-07-02 15:33
一下代码是功能同等于 #!/usr/bin/perl -w, 适用ksh, sh(这段代码摘自perldoc perlrun) 。 因为有些系统不能识别 #!.  请高手解释一下是如何工作的。 此断代码实际上是 以shell 代码运行的。 当作perl代码时直接就被忽略了(因为 if 0 这条语句)
                   eval '(exit $?0)' && eval 'exec perl -wS $0 ${1+"$@"}'
                    & eval 'exec /usr/bin/perl -wS $0 $argv:q'
                            if 0;

1. eval '(exit $?0)' 作用是什么?
2. 单个的 '&' 是做什么的,难道不是后台运行吗?
3. 为什么用  ${1+"$@"}, 而不直接用 "$@"?
4.  ‘if 0;’ 在shell 中语法是不对的,为什么运行在这里没问题呢?
...

正如你说的,因为最后一行是 if 0,所以这行在 perl 下是不会运行了。
先回答你的你 4 个问题。之所以在 shell 里没问题,是因为这段代码很巧妙的由三种语言写成,一种是整个三行是 Perl 语言,前两行是 Csh 代码,仅有第一行是 bash 代码。做到这一点的关键是 exec,当 csh 或者 bash 运行 exec 后就用 Perl 进程替换掉了原来的 Shell 进程,后面的那个 if 0; 永远也不会作为 Shell 代码被执行,因此可以说它并不属于 Shell 代码的一部分。
接着是第一个问题,这个表达示的功能是使得 bash 运行
  1. eval 'exec perl -wS $0 ${1+"$@"}'
复制代码
而使得 Csh 运行
  1. & eval 'exec /usr/bin/perl -wS $0 $argv:q
复制代码
这一行代码,
  1. exit $?0
复制代码
就是用来根据真假值来判断用的是什么 Shell 的,因为 Bash 把 0 当成真,Csh 把 1 当成真。
  1. exit $?0
复制代码
相当于
  1. exit 0
复制代码
至于为什么不直接用
  1. exit 0
复制代码
我不太清楚,因为我对 Bash 与 Csh 都不太清楚。不过,这显然是于某种 Shell 相关的。
第2 个问题的答案是因为为了办到刚才回答的第1问的答案,我们不能用
  1. &&
复制代码
,但是又必须让这一行对Shell 没什么太大的影响,而且可以保证这三行是一个完整的 Perl 代码,所以选择
  1. &
复制代码
正好可以做到这一点,它是为了满足语法而存在的东西。
至于第三问,我也不是太清楚,这应该与某种 Shell 相关(比如说可能是 ksh 的要求)(如果不是与 Bash 相关的话)。

论坛徽章:
0
4 [报告]
发表于 2012-07-03 15:05 |只看该作者
回复 3# Monox

exec 和 "&" 的解释非常好。 大体明白这段代码是如何工作的了。 非常感谢。
   

论坛徽章:
95
程序设计版块每日发帖之星
日期:2015-09-05 06:20:00程序设计版块每日发帖之星
日期:2015-09-17 06:20:00程序设计版块每日发帖之星
日期:2015-09-18 06:20:002015亚冠之阿尔艾因
日期:2015-09-18 10:35:08月度论坛发贴之星
日期:2015-09-30 22:25:002015亚冠之阿尔沙巴布
日期:2015-10-03 08:57:39程序设计版块每日发帖之星
日期:2015-10-05 06:20:00每日论坛发贴之星
日期:2015-10-05 06:20:002015年亚冠纪念徽章
日期:2015-10-06 10:06:482015亚冠之塔什干棉农
日期:2015-10-19 19:43:35程序设计版块每日发帖之星
日期:2015-10-21 06:20:00每日论坛发贴之星
日期:2015-09-14 06:20:00
5 [报告]
发表于 2012-07-03 17:12 |只看该作者
本帖最后由 MMMIX 于 2012-07-03 17:23 编辑
gangcai 发表于 2012-07-02 15:33
3. 为什么用  ${1+"$@"}, 而不直接用 "$@"?


${1+"$@"} 的意思是若 $1 不为 unset(存在位置参数),则展开为 "$@";否则就展开为 nothing(相当于没有位置参数)。若是直接用 "$@",在某些 shell 下,可能会传入一个值为 "" 的位置参数(Bash/Dash 都不存在这个问题)。

论坛徽章:
0
6 [报告]
发表于 2012-07-03 18:34 |只看该作者
回复 5# MMMIX


    我也曾经这样怀疑过。但不确定。 谢谢您的解释。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP