Перевод переключателя csh на Perl

Сейчас я перевожу некоторые скрипты с 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 ignored», выводимое на терминал, как и ожидалось.

Любые идеи?


person moadeep    schedule 18.02.2013    source источник
comment
Perl 5.8.8 ... устарел в следующем выпуске Perl - вы пропустили следующий выпуск Perl. И еще несколько. Сейчас мы на Perl 5.16.2. Switch.pm (что, как я полагаю, вы имели в виду под Strict) был удален из ядра в 5.14. Обновите и используйте данный / когда (доступно с 5.10 и далее, хотя вам понадобится более новая версия с меньшими ошибками).   -  person Quentin    schedule 18.02.2013
comment
@ Квентин Да, я так думаю. Я использую красную шляпу, а последняя версия - perl 5.8.8.   -  person moadeep    schedule 18.02.2013
comment
Установите более новую. Используйте Perlbrew, чтобы изолировать его от системного Perl. (Поскольку (1) возиться с системой Perl может сломать хрупкие сценарии администрирования дистрибутива и (2) Red Hat имеет очень плохую репутацию, когда дело доходит до упаковки Perl).   -  person Quentin    schedule 18.02.2013
comment
Утверждается, что ваше сообщение об ошибке исходит от «sh», оболочки Bourne Shell, а не от perl или csh. Поскольку я не вижу "#!" line, вы уверены, что вызываете Perl?   -  person tjd    schedule 18.02.2013
comment
@tjd Я обнаружил свою ошибку. Да, я вызываю perl в начале скрипта. Я только выделил часть кода, содержащую переключатель   -  person moadeep    schedule 18.02.2013
comment
@ Квентин. Было бы желательно использовать системный Perl, поскольку сценарий будет использоваться в масштабах всей системы и будет доступен 20-ти пользователям на таком же количестве компьютеров.   -  person moadeep    schedule 18.02.2013
comment
@moadeep - Я бы серьезно посмотрел на развертывание нового Perl так же, как вы тогда развертывали бы любое другое программное обеспечение, не относящееся к Red Hat.   -  person Quentin    schedule 18.02.2013
comment
Я бы посоветовал вам полностью обойти обработку переключателей и правильно обработать параметры команды с помощью Getopt :: Long.   -  person Andy Lester    schedule 18.02.2013
comment
@Andy Lester 2 мог бы Getopt :: Long работать в цикле while, а не при первом выполнении скрипта. Скрипт показывает кинофильмы изображений, и этот цикл даст точный контроль над тем, как изображения отображаются, например, ускоряет фильм (т.е. сокращает время между кадрами)   -  person moadeep    schedule 19.02.2013
comment
Я ответил ниже на заданный вами вопрос, но теперь похоже, что вам нужен цикл событий. Это будет постоянно слушать вашу клавиатуру и ждать команд.   -  person Joel Berger    schedule 19.02.2013


Ответы (3)


Тем, кто говорит: Получите более новую версию Perl): не у всех есть контроль над своими системами. Если OP находится в Red Hat, вероятно, это компьютер компании, что означает, что OP не контролирует его. Самый последний выпуск Perl для Redhat - 5.8.8. Мы можем считать его устаревшим и устаревшим, но многие корпоративные версии Perl используют его.

У меня есть последняя и самая лучшая версия Perl на моих локальных машинах, которые я контролирую, но мне приходится писать с использованием синтаксиса Perl 5.8.8, и я должен предположить, что не могу загрузить какие-либо модули CPAN.

Это настоящая жизнь, и это отстой. Но с этим нужно жить ...


Во-первых, Perl и Csh - это два полностью языков, и построчный перевод одного языка на другой - не лучшая идея. Perl - гораздо более мощный язык, и было бы неплохо использовать многие из его функций для улучшения вашего скрипта csh.

Если вы разбираете командную строку, попробуйте использовать модуль Getopts :: Long, который сделает за вас большую часть работы и доступен в Perl 5.8.8. Это может сделать именно то, что вы пытаетесь сделать с оператором switch, и потребует гораздо меньше работы и намного более гибко.

Я бы избегал использования оператора switch в Perl. Это никогда не работало очень хорошо. Новый given/when материал работает лучше, но, увы, он доступен только с Perl 5.10.

Вместо этого забудьте о переключателях и используйте структуру 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` одновременно.

person David W.    schedule 18.02.2013
comment
Последний выпуск Perl для Redhat - 5.8.8. На самом деле это неточно. Если вы запустите RHEL 6.x, то у вас будет 5.10.1. Все еще не очень актуально, но это огромное улучшение по сравнению с 5.8.8. - person Dave Cross; 19.02.2013
comment
Если это правда, по крайней мере, в нем будут say, when/given, переменные состояния, Date :: Timepiece и другие приятные улучшения. Несколько недель назад я спросил наших технических специалистов, могут ли они обновить недавно созданную машину RHEL с Perl 5.8.8 (или, может быть, с версии 5.8.9), и мне сообщили, что это последняя версия Perl, сертифицированная для RHEL. Я попытался подтвердить это, но не смог найти список пакетов и версий RHEL. Я знаю, что Solaris и другие коммерческие пакеты Unix / Linux тоже сильно отстают. В качестве SVN-сервера мы установили SUSE, и у него был SVN 1.3, а SVN 1.7 только что вышел. - person David W.; 19.02.2013
comment
О, это определенно правда. Я использую серверы Centos 6.3 (Centos - это бесплатная версия RHEL) и в стандартной комплектации Perl 5.10.1 - см. mirrorservice.org/sites/mirror.centos.org/6.3/os/x86_64/ - person Dave Cross; 19.02.2013
comment
К сожалению, мы, по-видимому, все еще используем RHEL 5 и в ближайшее время не перейдем на него. Это одно из самых больших разочарований в корпоративном мире. RHEL 6 вышел в конце 2010 года, но еще не был сертифицирован нашей системной командой для нашего использования. - person David W.; 20.02.2013
comment
Знаете, вам не нужно полагаться на системную версию Perl. Вы всегда можете установить свою версию. Взгляните на Perlbrew, который упрощает эту задачу. В качестве альтернативы доступны другие вакансии :-) - person Dave Cross; 21.02.2013
comment
Вы не всегда контролируете машины, на которых работаете, особенно в корпоративной производственной среде. Вас поймают за установку программ на производственные машины без разрешения, и вы не только потеряете работу, но и столкнетесь с трудностями при получении новой. Плюс, если это был банк, возможны проблемы с законом. - person David W.; 21.02.2013
comment
О, я не это предлагал. Я предполагал, что даже если системные администраторы не будут обновлять системный Perl (что является для них вполне разумной позицией), они могли бы рассмотреть возможность использования perlbrew для установки чего-то более свежего для вашего проекта. - person Dave Cross; 21.02.2013

while(<>){} в perl не эквивалентно while(1) в csh. while(<>) в perl эквивалентен while(defined($_ = <>)), который является чтением и проверкой, чтобы убедиться, что eof не был достигнут. попробуйте заменить while(<>) на while(1).

person user1937198    schedule 18.02.2013

Для более крупной программы с много вариантов. В противном случае для делегирования может работать хэш подрефов, а не оператор switch.

person Joel Berger    schedule 19.02.2013