0

I am currently translating some scripts from csh to perl. I have come across one script which has the following switch control

#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

I have Perl 5.8.8 installed on my system and using use Strict;which I know may become deprecated in the next perl release, I have tried the following

#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>);

      }


  }

When I press return I get the required options printed to the terminals. However, when I type any option into STDIN - e.g a, h or d - I get no response. When I enter retirn - I get the message "h ignored" printed to the terminal as expected.

Any ideas?

moadeep
  • 3,988
  • 10
  • 45
  • 72
  • 5
    "Perl 5.8.8 … deprecated in the next perl release" — You've missed the next Perl release. And several others. We're on Perl 5.16.2 now. `Switch.pm` (which I assume is what you meant by `Strict`) was removed from core in 5.14. Upgrade and use [given/when](http://stackoverflow.com/questions/844616/obtain-a-switch-case-behaviour-in-perl-5) (available from 5.10 onwards, although you'll want a newer, less buggy version). – Quentin Feb 18 '13 at 15:30
  • @Quentin Yes I think so. I am using red hat and perl 5.8.8 was the latest version – moadeep Feb 18 '13 at 15:36
  • 1
    Install a newer one. Use [Perlbrew](http://perlbrew.pl/) to sandbox it away from the system Perl. (Since (1) Messing with the system Perl can break fragile distro admin scripts and (2) Red Hat have a very poor track record when it comes to packaging Perl). – Quentin Feb 18 '13 at 15:38
  • Your error message claims to be coming from 'sh', the Bourne Shell, not from perl or csh. As I'm seeing no '#!' line, are you sure you're calling perl? – tjd Feb 18 '13 at 16:18
  • @tjd I tracked down my error. Yes I am calling perl at the start of the script.I have only highlighted the section of code containing the switch – moadeep Feb 18 '13 at 16:24
  • @Quentin. Using the system perl would be desirable as the script would be used system wide and would be available to 20ish users on as many computers – moadeep Feb 18 '13 at 16:26
  • @moadeep — I'd seriously look at deploying a newer Perl in the same was as you would deploy any non-Red Hat software then. – Quentin Feb 18 '13 at 16:28
  • 1
    I would suggest you bypass the switch-handling entirely and properly process the command options with Getopt::Long. – Andy Lester Feb 18 '13 at 17:02
  • @Andy Lester 2 would Getopt::Long work in a while loop rather than on first execution on the script. The script shows cine movies of images and this loop will give fine control to how the images are displayed eg accelerate the movie (i.e shorten the time between frames) – moadeep Feb 18 '13 at 20:00
  • I answered below about the question you asked, but now it sounds like you want an event loop. This would listen to your keyboard continuously and wait for commands. – Joel Berger Feb 19 '13 at 01:46

3 Answers3

2

To those who say Get a newer version of Perl): Not everyone has control over their systems. If the OP is on Red Hat, it's probably a company machine which means the OP doesn't have control over it. The latest releas of Perl on Redhat is 5.8.8. We might consider it antique and obsolete, but many corporate version of Perl use it.

I have the latest and greatest versions of Perl on my local machines that I control, but I have to write using Perl 5.8.8 syntax, and I have to assume I can't download any CPAN modules.

This is real life, and it can suck. But, you have to live with it...


First off, Perl and Csh are two completely languages and doing a line-by-line translation of any language into another is not a good idea. Perl is a much more powerful language, and it might be nice to use many of the features to improve your csh script.

If you are parsing a command line, look into using the module Getopts::Long which will do a lot of the work for you and is available in Perl 5.8.8. This may do exactly what you're trying to do with the switch statement and take a lot less work and is a lot more flexible.

I would avoid using the switch statement in Perl. It never really worked very well. The new given/when stuff works better, but alas, it's only available since Perl 5.10.

Instead, forget the switch stuff and use an if/elsif structure then case statement:

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 ...

It's not as elegant as a switch statement, but it does the job and is easy to understand and maintain. Also take advantage of using regular expression matching. For example $command =~ /^(fq)$/i is checking to see if$commandis equal toF,f,q, orQ` all at the same time.

David W.
  • 105,218
  • 39
  • 216
  • 337
  • "The latest release of Perl on Redhat is 5.8.8." Actually, that's inaccurate. If you run RHEL 6.x then you'll have 5.10.1. Still not particularly up to date, but a *huge* improvement on 5.8.8. – Dave Cross Feb 19 '13 at 10:34
  • If that's true, at least it'll have `say`, `when/given`, state variables, `Date::Timepiece, and other nice improvements. A few weeks ago, I asked our Techs if they could update a newly build RHEL machine from Perl 5.8.8 (or maybe it was 5.8.9) and I was informed that is the latest version of Perl that is certified for RHEL. I tried to confirm that, but couldn't find a list of RHEL packages and versions. I know Solaris and other commercial Unix/Linux packages are far behind too. As a SVN Server, we installed SUSE, and it had SVN 1.3, and SVN 1.7 had just come out. – David W. Feb 19 '13 at 14:19
  • Oh, it's definitely true. I'm running Centos 6.3 servers (Centos is the free version of RHEL) and that has Perl 5.10.1 as standard - see http://www.mirrorservice.org/sites/mirror.centos.org/6.3/os/x86_64/Packages/ – Dave Cross Feb 19 '13 at 14:55
  • Unfortunately we're still apparently on RHEL 5 and won't be switching anytime soon. It's one of the big frustrations of the corporate world.RHEL 6 was out in the end of 2010, but it hasn't been _certified_ by our systems team yet for our use. – David W. Feb 20 '13 at 01:33
  • You don't need to rely on the system version of Perl, you know. You can always install your own version. Take a look at "perlbrew" which makes this easy. Alternatively, other jobs are available :-) – Dave Cross Feb 21 '13 at 09:17
  • You don't always control the machines you work on -- especially in a corporate production environment. You get caught installing programs without permission on production machines, and you'll not only lose your job, but might find it difficult getting another one. Plus, if this was a bank, possible legal troubles. – David W. Feb 21 '13 at 15:51
  • Oh, that's not what I was suggesting. I was suggesting that even if the sysadmins wouldn't upgrade the system Perl (which is a perfectly reasonable position for them to take) then they might consider using perlbrew to install something more recent for your project. – Dave Cross Feb 21 '13 at 17:05
0

while(<>){} in perl is not equivalent to while(1)in csh. while(<>) in perl is equivalent to while(defined($_ = <>)) which is a read and a check to see that eof has not been reached. try replacing while(<>) with while(1).

user1937198
  • 4,987
  • 4
  • 20
  • 31
0

You might look at something like App::Cmd for a larger program with lots of options. Otherwise, a hash of subrefs might work for delegation rather than a switch statement.

Joel Berger
  • 20,180
  • 5
  • 49
  • 104