【问题标题】:How does : # use perl eval 'exec perl -S $0 ${1+"$@"}' set the perl version?: # use perl eval 'exec perl -S $0 ${1+"$@"}' 如何设置 perl 版本?
【发布时间】:2020-08-24 16:08:45
【问题描述】:

我必须调试一个旧的 perl 脚本,显然它正在以我不理解的方式设置 perl 的版本...

: # use perl
    eval 'exec perl -S $0 ${1+"$@"}'
    if 0;

perl -h 表示-S 的意思是“使用 PATH 环境变量查找程序文件”。 $0 是当前程序。我读过$@ 的意思是“来自最后一个eval 命令的Perl 语法错误消息”。但是他们为什么要加 1 呢?这一切如何结合在一起?它在做什么?

我必须调试的部分原因在于它选择了我不想要的旧版本的 perl。对于其他一切,我们使用#!/usr/bin/env perl,我怀疑它可能正在做同样的事情。我还怀疑我的解决方案可能在于修复$PATH(或防止弄乱它的代码弄乱它)。但我想进一步了解它现在是如何选择版本的。

感谢您的帮助!

【问题讨论】:

  • 查看perlvar 了解$@ 的确切含义(但是,正如Shawn 的回答所示,第二行是由shell 运行的,所以$@ 是shell 的,而不是Perl 的。)例如,${1+"$@"} 技巧的更详细说明见 here
  • Re "我读过 $@ 的意思",在 Perl 中是的,但是 Perl 从不执行该命令(因为 if 0)。它由 shell 执行的命令(如果 shebang 行以某种方式被忽略)。

标签: shell perl


【解决方案1】:

这是为了运行路径中首先出现的任何版本的 perl,方法是首先将脚本视为 shell 脚本,然后执行 perl。在这种情况下,${1+"$@"} 是传递给脚本的参数(如果有)。

来自 bash 手册:

${parameter:+word}

如果参数为null或未设置,则不替换任何内容,否则替换单词的扩展。

省略冒号会导致仅对未设置的参数进行测试

perlrun中有一个类似的例子:

此示例适用于具有与 Bourne shell 兼容的 shell 的许多平台:

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

系统忽略第一行并将程序提供给/bin/sh,后者继续尝试将 Perl 程序作为 shell 脚本执行。 shell 像普通的 shell 命令一样执行第二行,从而启动 Perl 解释器。在某些系统上,$0 并不总是包含完整的路径名,所以-S 告诉 Perl 在必要时搜索程序。 Perl 定位程序后,它会解析这些行并忽略它们,因为变量$running_under_some_shell 永远不会为真。如果程序将由 csh 解释,则需要将 ${1+"$@"} 替换为 $*,即使这不理解参数列表中的嵌入空格(等)。要启动 sh 而不是 csh,某些系统可能必须替换 #! line 与仅包含冒号的行,Perl 将礼貌地忽略它。

使用/usr/bin/env 是做同样事情的另一种方式,是的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-18
    • 2017-02-18
    • 2011-08-30
    • 2010-09-16
    • 1970-01-01
    • 2014-11-23
    • 1970-01-01
    相关资源
    最近更新 更多