【问题标题】:Translating csh switch to perl将 csh 开关转换为 perl
【发布时间】:2013-02-19 09:42:46
【问题描述】:

我目前正在将一些脚本从 csh 翻译成 perl。我遇到了一个具有以下开关控制的脚本

#And now some control
set get_command = h
set finish = 0

while (1)

    switch ($get_command)
    case "h":
    case "H":
    set cine_command = ""

cat << EOF
Control synchronised cine by (case insensitive):
  A        - A view data
  B        - B view data
  a        - accelerate
  d        - decelerate
  r        - real time heart rate
  <num>    - rate (frames per second)
  i        - toggle interpolation
  s        - step through (may lose a little synchronisation)
  c        - continue (restart) after stepping
  y        - reverse direction
  h        - help (repeat this)
  f        - finish (quit)
  q        - quit (finish)
  <return> -  quit
EOF

    breaksw

    case "":
    case "f":
    case "F":
    case "q":
    case "Q":
        set cine_command = '-f'
        set finish = 1
    breaksw

    case "a":
        set cine_command = '-a'
    breaksw

    case "d":
    case "D":
        set cine_command = '-d'
    breaksw

    case "r":
        case "R":
        set cine_command = "-t $time_per_frame"
    breaksw

    case "i":
    case "I":
        set cine_command = '-i'
    breaksw

    case "s":
    case "S": 
        set cine_command = "-s"
    breaksw

    case "c":
    case "C":
        set cine_command = "-c"
    breaksw

    case "y":
    case "Y":
        set cine_command = "-y"
    breaksw

    case '[0-9]*':
        set cine_command = "-r $get_command"
    breaksw

    default:
        echo "$get_command ignored"
        set cine_command = ""
    endsw

    if ('$cine_command' != '') then
    select_tv $FIRST_TV
    cine $cine_command
    select_tv $SECOND_TV
    cine $cine_command
    endif

    #
    # If we're stopping then get out of this loop.
    #
    if ($finish) break

    echo -n "cine > "
    set get_command = $<

end

我的系统上安装了 Perl 5.8.8 并使用 use Strict;,我知道它可能会在下一个 perl 版本中被弃用,我尝试了以下方法

#Add some fine control to script
my $get_command = 'h';
my $finish = 0;
my $cine_command;

while(<>)
  {
      switch ($get_command)
      {

    case [hH] {$cine_command = "";}

    print STDOUT << 'END';
Control synchronised cine by (case insensitive):
  A        - A view data
  B        - B view data
  a        - accelerate
  d        - decelerate
  r        - real time heart rate
  <num>    - rate (frames per second)
  i        - toggle interpolation
  s        - step through (may lose a little synchronisation)
  c        - continue (restart) after stepping
  y        - reverse direction
  h        - help (repeat this)
  f        - finish (quit)
  q        - quit (finish)
  <return> -  quit
END

      case [fFqQ] 
        {
         $cine_command = '-f';
         $finish = 1;
         }

      case "a"
        {
         $cine_command = '-a';
        }

      case [dD]
        {
         $cine_command = '-d';
         }

      case [rR]
        {
         $cine_command = "-t $time_per_frame";
         }

      case [iI]
        {
         $cine_command = '-i';
         }

      case [sS]
        {
         $cine_command = '-s';
         }

      case [cC]
        {
         $cine_command = '-c';
         }

      case [yY]
        {
         $cine_command = '-y'
         }

      case /\d/
        {
         $cine_command = "-r $get_command";
        }

      else 
        {
          print "$get_command ignored\n";
          $cine_command = "";
          }

    if ($cine_command ne "") 
      {
        `select_tv $FIRST_TV`;
        `cine $cine_command`;
        `select_tv $SECOND_TV`;
        `cine $cine_command`;
      }

    exit if( $finish == 1);

    print STDOUT "cine > \n";
    chomp(my $get_command = <STDIN>);

      }


  }

当我按下回车键时,我会在终端上打印所需的选项。但是,当我在 STDIN 中输入任何选项时——例如 a、h 或 d——我没有得到任何响应。当我输入 retirn - 我得到消息“h被忽略”按预期打印到终端。

有什么想法吗?

【问题讨论】:

  • "Perl 5.8.8 … 在下一个 perl 版本中已弃用" — 你错过了下一个 Perl 版本。还有其他几个。我们现在使用 Perl 5.16.2。 Switch.pm(我假设你的意思是 Strict)在 5.14 中从核心中删除。升级并使用given/when(从 5.10 开始可用,尽管您需要更新的、错误更少的版本)。
  • @Quentin 是的,我想是的。我使用的是 red hat,perl 5.8.8 是最新版本
  • 安装一个较新的。使用Perlbrew 将其从系统 Perl 中分离出来。 (因为 (1) 与 Perl 系统混用会破坏脆弱的发行版管理脚本,并且 (2) Red Hat 在打包 Perl 方面的记录非常差)。
  • 您的错误消息声称来自“sh”,即 Bourne Shell,而不是来自 perl 或 csh。正如我所见,没有“#!”行,你确定要调用 perl 吗?
  • 我建议您完全绕过开关处理并使用 Getopt::Long 正确处理命令选项。

标签: perl csh


【解决方案1】:

对于那些说获取更新版本的 Perl)的人:并不是每个人都可以控制他们的系统。如果 OP 在 Red Hat 上,它可能是公司机器,这意味着 OP 无法控制它。在 Redhat 上的 最新 Perl 版本是 5.8.8。我们可能认为它过时且过时,但许多企业版 Perl 都在使用它。

我在我控制的本地机器上拥有最新最好的 Perl 版本,但我必须使用 Perl 5.8.8 语法编写,而且我不得不假设我无法下载任何 CPAN 模块。

这是真实的生活,它可能很糟糕。但是,你必须忍受它......


首先,Perl 和 Csh 完全是两种语言,将任何一种语言逐行翻译成另一种语言并不是一个好主意。 Perl 是一种更强大的语言,使用许多功能来改进您的 csh 脚本可能会很好。

如果您正在解析命令行,请考虑使用模块Getopts::Long,它将为您完成大量工作,并且在 Perl 5.8.8 中可用。这可能完全符合您对 switch 语句的要求,而且工作量更少,而且更灵活。

我会避免在 Perl 中使用 switch 语句。它从来没有真正运作得很好。新的given/when 东西效果更好,但可惜的是,它仅在 Perl 5.10 之后可用。

相反,忘记 switch 的东西并使用 if/elsif 结构然后是 case 语句:

my $usage =<<USAGE;
Control synchronised cine by (case insensitive):
  A        - A view data
  B        - B view data
  a        - accelerate
  d        - decelerate
  r        - real time heart rate
  <num>    - rate (frames per second)
  i        - toggle interpolation
  s        - step through (may lose a little synchronisation)
  c        - continue (restart) after stepping
  y        - reverse direction
  h        - help (repeat this)
  f        - finish (quit)
  q        - quit (finish)
  <return> -  quit
USAGE

$cine_command;
$finish;
while ( my $command = get_command() ) {
    if   ( $command =~ /^h$/i ) {
        print "$usage\n";
        exit 0;
    }
    elsif ( $command =~ /^(fq)$/i ) {
        $cine_command = '-f'
        $finish = 1
    }
    elsif ( $command =~ /^a$/i ) {
        $cine_command = '-a';
    }
    elsif ...

它不像 switch 语句那样优雅,但它可以完成工作并且易于理解和维护。还可以利用正则表达式匹配。例如$command =~ /^(fq)$/i is checking to see if$commandis equal toF,f,q, orQ` 同时进行。

【讨论】:

  • "Redhat 上 Perl 的最新版本是 5.8.8。"实际上,这是不准确的。如果您运行 RHEL 6.x,那么您将拥有 5.10.1。仍然不是特别最新,但对 5.8.8 有巨大的改进。
  • 如果是真的,至少它会有saywhen/given、状态变量、`Date::Timepiece 和其他不错的改进。几周前,我问我们的技术人员是否可以从 Perl 5.8.8(或者可能是 5.8.9)更新新构建的 RHEL 机器,我被告知这是经过 RHEL 认证的最新版本的 Perl。我试图确认这一点,但找不到 RHEL 软件包和版本的列表。我知道 Solaris 和其他商业 Unix/Linux 软件包也远远落后。作为 SVN Server,我们安装了 SUSE,它有 SVN 1.3,而 SVN 1.7 刚刚出来。
  • 哦,这绝对是真的。我正在运行 Centos 6.3 服务器(Centos 是 RHEL 的免费版本)并且标准配置为 Perl 5.10.1 - 请参阅 mirrorservice.org/sites/mirror.centos.org/6.3/os/x86_64/…
  • 不幸的是,我们显然仍在使用 RHEL 5,并且不会很快切换。这是企业界最大的挫折之一。RHEL 6 于 2010 年底推出,但尚未得到我们的系统团队的认证供我们使用。
  • 你不需要依赖 Perl 的系统版本,你知道的。您始终可以安装自己的版本。看看“perlbrew”,这很容易。或者,其他工作可用:-)
【解决方案2】:

perl 中的while(&lt;&gt;){} 不等同于 csh 中的while(1)。 perl 中的while(&lt;&gt;) 等价于while(defined($_ = &lt;&gt;)),这是一个读取和检查以查看是否未达到eof。尝试将while(&lt;&gt;) 替换为while(1)

【讨论】:

    【解决方案3】:

    您可能会查看App::Cmd 之类的内容,以了解具有很多选项的大型程序。否则,子引用的散列可能对委托而不是 switch 语句起作用。

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      相关资源
      最近更新 更多