话题:
请问${1+"$@"}是什么意思啊?
#!/usr/bin/perl
eval 'exec /usr/bin/perl -wS $0 ${1+"$@"}'
if $running_under_some_shell;
以下是flw版主的回复:
这几行程序包含了太多的技巧。
的确需要很深的功力才能看得懂。
首先解释一下,# 打头的行在 shell 中表示该行是注释行,但是如果该脚本具有可执行权限,
而直接执行(如 C 的 exec* 系列系统调用,或者 shell 下直接敲脚本名称)的时候,该行
起到指示解释器的作用。在本例中,指定解释器是 /usr/bin/perl(假设用户的系统上已经
安装了 Perl 并且安装位置就在 /usr/bin/perl 否则该脚本无论如何都是无法执行的)
当一个用户拿到脚本时,根据个人习惯和知识水平的不同,可能会有以下三种执行脚本的方法:
执行方式 1,./foo
使用 chmod +x foo 赋予了脚本可执行权限之后,就可以用这种方法来执行。
前面说了,这种方式执行的时候,OS 会去按照脚本第一行 #! 的指示去寻找 interpreter
的位置,在这里也就是 /usr/bin/perl,所以一旦找到 /usr/bin/perl,后面的两行
eval 'exec /usr/bin/perl ......' if $rrunning_under_some_shell; 就会被当作 Perl
代码来执行。因为 $running_under_some_shell 这个变量没有被定义过,因此它的值为
undef,也就是说 if 修饰符会失败,从而导致 eval 这句不会被执行。因此在这种情况下,
如果系统中已经安装了 Perl 并且 Perl 的位置就是在 /usr/bin/perl 的话,这两行就相当于什么都没有
注意在 Perl 中换行符作为空白符是可以任意添加的,所以这两行合起来实际上是一个完
整的语句。但是这里面有个技巧,它故意写成了两行,原因在下面解释。
执行方式 2,perl foo
当用户已经知道这个脚本是一个 Perl 脚本的时候,就可以用这种方式执行。这种方式和
第一种方式基本相同,唯一不同的地方就是 #!/usr/bin/perl 会被当成普通的 Perl 注释。
执行方式 3,sh foo
这种方式下,用户误以为 foo 是一个 shell 脚本,因此调用了 shell 来执行这个脚本。
此时,第一行 #! 会被 shell 当作普通的注释而忽略。在这种情况下,eval 会被当作一个
shell 命令来解释,它的参数 'exec /usr/bin/perl ....' 则是一个合法的 shell 命令,
其作用就是重新调用 /usr/bin/perl 来解释此脚本,shell 参数 $0 在这种情况下其实就是
脚本自身的名称。而 "$@" 也就等于 "$1" "$2" "$3" ... 也就是脚本的参数(注)。也就是说:
如果该脚本被错误地当作 shell 脚本来执行,那也没问题,因为它也是一个
合法的 Perl 脚本 注意这里故意把 if 修饰符另起一行来写,是为了保证 eval
那行是一个正确的 shell 语句。因为 eval 那行一旦执行成功,exec 会覆盖当前进程,
因此 if 这一行根本就没有执行的机会,也就不会出错。
总结:
这么写的作用,是为了让这个脚本既能用 perl 来解释,也能用 shell 来解释。如果当
用 perl 来解释,固然正确,但是即使用 shell 来解释,也不仅不会出错,还会得到同
样的结果。
注:这个地方通常写作 "$@" 但是在你这个例子里不知为何写成 ${1+"$@"},也许另有深意,我
查了一下,在我的系统(Debian 4.0)中,两种写法都有。如果你有兴趣,可以去 shell
版再请教一下 "$@" 和 ${1+"$@"} 的区别。
阅读(1549) | 评论(0) | 转发(0) |