tags:

views:

141

answers:

5

I have a small program:

#!/user/bin/perl

use strict;
system ("clear");
my($option, $path);

do
{
    print "\tEnter the number of your chosen option:\n";    
    print "\n";
    print "\tOption\t\tCommand\n";
    print "\t======\t\t=======\n";
    print "\t1\t\tDate\n";
    print "\t2\t\tDirectory Listing\n";
    print "\t3\t\tCalendar\n";
    print "\t4\t\tVi Editor\n";
    print "\t5\t\tCalculator\n";
    print "\t6\t\tExit\n\n";
    chomp($option=<STDIN>);

    SWITCH:
    {
        ($option =="1") and do
        {
            system(date);           
            last;
        };

        ($option =="2") and do
        {
            print "Enter the path:"; ############################
            chomp($path=<STDIN>);    #This is giving me an error#
            system(ls $path);        ############################
            last;
        };  

        ($option =="3") and do
        {
            system(cal);
            last;
        };

        ($option =="4") and do
        {
            system(vi);
            last;
        };

        ($option =="5") and do
        {
            system(bc);
            last;
        };      
    }   
}while ($option!=6);

print "Goodbye!\n";
sleep 2;

First question: Can anyone help me how to write the proper command to create a directory listing in case 2.

Second Question: Why do I get a loop if I use

$date = `date`;
print "$date"; 

instead of

system(date);
+2  A: 

You could read the path like:

chomp($path=<STDIN>);
system("ls $path");

Not sure why you'd get the loop for $date =date;print "$date";. But I don't think there's a date function unless you're using a package for it. You can show a time like:

my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
$year += 1900;
$mon += 1;
printf "%04d-%02d-%02d %02d:%02d:%02d", 
       $year, $mday, $mon, 
       $hour, $min, $sec;

On most unix systems perl resides in /usr/bin, without the e in user, so you might consider double-checking the first line of your script.

Andomar
+3  A: 

You should be able to solve a lot of your problems by remembering to put quotes around literal arguments to system():

system("date");
system("ls $path");

and the same for most other places you call system() (your first call to system("clear") is correct).

It is a quirk of Perl that calling something like system(cal) works at all, because the unquoted cal is treated as a "bareword" by Perl, which happens to be roughly equivalent to a string when passed to a function such as system(). Relying on this behaviour would be terribly bad practice, and so you should always quote literal strings.

Greg Hewgill
A: 

I can not reproduce your loop with:

$date =date;print "$date"; 

I doubt that is exactly how you coded it since I get a compile error with use strict;. If you can show a reduced code example which still illustrates the problem, we could help debug it further.

If you are trying to capture the output of an external command into a variable, you could use backticks or qx:

my $date = qx(date);
print "$date";

On a side note, whenever I see a series of print statements, I think here-doc:

print <<"EOF";
Enter the number of your chosen option:
    Option Command
    ====== =======
    1      Date
    2      Directory Listing
    etc...
EOF

A little easier to read and maintain, no?

Finally, it is also a good idea to use warnings;.

toolic
A: 

The first couple of suggests I have are, first like others have already suggested, use warnings is strongly encouraged. Older Perl interpreters may require you use the older form #!/usr/bin/perl -w as the first line of your Perl script. Second, there is a Switch module available, to make the switch statement look less ugly. I've also shown usage of subroutines to clean up the appearance of the program.

I've attached a alternative version of your script with some potential suggestions. Note it uses a slightly different alternative for switch. If available, I'd recommend using the Switch module. It includes a different way of printing the time, and of course fixes your problem with the system calls.

I hope that helps.

#!/usr/bin/perl

use strict;
use warnings;       # otherwise /usr/bin/perl -w in first line

sub menu() {
    print <<EOM;
    Enter the number of your chosen option:

    Option      Command
    ======      =======
    1       Date
    2       Directory Listing
    3       Calendar
    4       Vi Editor
    5       Calculator
    6       Exit
EOM
}

sub showtime() {
    my $time = localtime;
    print $time,"\n";
}

sub listdir() {
    my $path;
    print "Enter the path: ";
    chomp($path = <STDIN>);
    system("ls $path");
    print "\n";
}

system("clear");

my $option;
do {
    menu();
    chomp($option = <STDIN>);

    # SWITCH:
    for ($option) {
        /1/ and do {
            showtime();
        };
        /2/ and do {
            listdir();
        };  
        /3/ and do {
            system("cal");
        };
        /4/ and do {
            system("vi");
        };
        /5/ and do {
            system("bc");
        };
        last;
    }   
} while ($option != 6);

print "Goodbye!\n";
sleep 2;
mctylr
+1  A: 

Your immediate problems were caused by quoting issues and the lack of use warnings in your script.

It's also worth noting that menu-driven scripts like yours are ideal candidates for dispatch tables. A dispatch table is a technique for defining actions as data. The actions are Perl subroutines. The data is usually a set of key-value pairs that end up getting stored in a hash.

The keys to the hash are the choices made by the user (menu items 1-6 in your case).

The values in the hash are called code references. There are two ways to set up these code references: (1) Directly in the dispatch table, using anonymous subroutines; or (2) using the &\foo syntax, which would create a reference to a subroutine named foo.

The handy thing about this approach is that your menu() method can be reused -- simply with a different dispatch table and a different usage message.

This example is so small that the benefit of reuse might not seem compelling, but the general technique of having data -- in the form of a dispatch table -- control program behavior is powerful in many contexts.

# Always use both of these.
use strict;
use warnings;

sub dispatch_table {
    return
        1 => sub { system 'date' },
        2 => \&ls_path,
        3 => sub { system 'cal'  },
        4 => sub { system 'vi'  },
        5 => sub { system 'bc'  },
        6 => sub { print "Goodbye!\n"; sleep 2 },
    ;
}

sub ls_path {
    print "\nEnter the path: ";
    chomp(my $path=<STDIN>);
    # Note quoting. To be super robust, you would
    # need to escape apostrophes in the path.
    system "ls '$path'";
}

sub usage_message {
    return "Choose wisely:

    Option  Command
    ======  =======
    1       Date
    2       Directory Listing
    3       Calendar
    4       Vi Editor
    5       Calculator
    6       Exit
";
}

sub menu {
    system 'clear';
    my %dt = dispatch_table();
    my $option;
    print usage_message();
    while (1){
        print "> ";
        chomp($option = <STDIN>);
        last if exists $dt{$option};
    }
    $dt{$option}->();
}

menu();
FM