Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I've been assigned a homework project which must allow up to 3 unix commands to be piped together and executed ive written some of it already but it is not limited to 3 commands and it seems to crash a little help would be appreciated thanks!
#!/usr/local/bin/perl -w # perl script to do a piping between up to 3 commands commands # use a # to separate commands on the command line $cmd = <STDIN>; #get input from the keyboard and store in variable +cmd chomp ($cmd); #remove carriage return @cmd = split (#, $cmd) #take array and decide on the pipe symbol wh +ich is # to separate commands $max = @cmd; #return the number of items in cmd $max = $max - 1; #max start at 0 # $pipe = $max - 1; #pipe start at 0 for ($j = 1; $j < $max - 1; $j++) # for loop used to create pipes { $INPIPE [$j] = $j; $OUTPIPE [$j] = $j; pipe $INPIPE [$j], $OUTPIPE [$j]; } for ($x = 1; $x < $max - 1; $x++) { #go through each part of the ar +ray if (fork == 0) { #first command for ($n = 1; $n < $max -1; $n++) #close all input pipes close INPIPE[$n]; for ($p = 2; $p < $max -1; $p++) #close all the output pipes close OUTPIPE[$p]; #except the last one close STDOUT; #close STDOUT and connect it to the open STDOUT ">&OUTPIPE[1]"; #first output pipe still open exec cmd[1]; #execute the command } elsif (x != 1 && x != max -1) #middle commands { for ($n = 1; $n < $max -1; $n++) #close all input pipes except +the if n != x -1 #previous one close INPIPE [$n]; if n != x #close all output pipes except the last one close OUTPIPE [$n]; close STDIN; #close STDIN and connect to previous pipe open STDIN ">&INPIPE[n -1]; close STDOUT; #close STDOUT and connect to last pipe open STDOUT ">&OUTPIPE[n]; exec cmd[x]; #execute the middle commands } elsif (x = max - 1) #last command { for ($n = 1; $n < $max -2; $n++) #close all input pipes except +the close INPIPE[$n]; #last one for ($p = 1; $p < $max -1; $p++) #close all output pipes close INPIPE[$p]; close STDIN; open STDIN ">&INPIPE[max -1]; exec cmd[$max - 1]; #execute the last command } } for ($d = 1; $d< $max - 1; $d++) { close $INPIPE[$d]; #close both input pipes close $OUTPIPE[$d]; #close both output pipes } for ($s = 1; $s < $max - 1; $s++) { wait; #wait for each child process }

Edit ar0n, 2001-06-20 Fixed formatting

Replies are listed 'Best First'.
Re: home work help
by mbond (Beadle) on Jun 20, 2001 at 16:43 UTC
    Okay, not gonna give away anything big here, and looking at the ocede the way it is is difficult (you should use the code tags around your code).

    $cmd = ;
    should be $cmd = <STDIN>;
    You should also check right from the start if there are more than 3 commands, and drop out right then and there.
    if ($max > 3) { print "exiting \n"; exit(1); }
    I know this isn't TOO much help, but it is homework. and IMHO pipes are a lot of fun to play with and figure out on your own. You can do a lot of really slick stuff with them. but if someone tells you how to do it, you lose the fun of figuring it out ... and you won't learn them as well.

    just skim though the cookbook, it gives you everything you need to work on this project if i remember correctly.

    mbond
Re: home work help
by buckaduck (Chaplain) on Jun 20, 2001 at 17:30 UTC
    One major problem is that you tend to forget the dollar sign before your variables. Take this line, for example:
    elsif (x = max - 1)
    You should probably add this line near the top, and then declare your variables with my:
    use strict;
    It will help you catch these kinds of errors.

    Update: I believe that if() statements and for() loops require curly braces, even if they are one-liners. Code such as this:

    for (...) if (...) ...blah...
    should be like this:
    for (...) { if (...) { ...blah... } }
    buckaduck
      Another way to handle one-liners would be to simply have the If statment afterwards
      print "foo \n" if $bar > 3;
      and for short things, this also works ... I like it to help keep the scrolling/line count down.
      for(my $I=0;$I<10;$I++) { print "foo \n" if $bar > 10 }
      I leave the semi-colon off for one line loops, just for readability sake, but include it on multiline loops. Strict doesn't yell about it, and its just a personal style thing.

      mbond
      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: home work help
by Davious (Sexton) on Jun 20, 2001 at 19:36 UTC

    You have (or someone has) obviously put a lot of work into this thus far if you've written all that perl code. That said, did they say you have to use perl at all?

    From the requirements you specified "allow up to 3 unix commands to be piped together and executed" it sounds like you want something more like this:

    cat /etc/passwd | grep 'yourusername' | gzip > me.gz

    Where we're "piping a bunch of unix commands together" to create a gzip of all the users in the passwd file that match 'yourusername'.

Re: home work help
by bikeNomad (Priest) on Jun 20, 2001 at 19:42 UTC
    Sounds like a lot of work. Why not just:
    my $cmd = <STDIN>; $cmd =~ tr/#\n/|/d; system($cmd);
    Of course, I'm missing the original requirements.