in reply to script debug

Hehe... first of all it would be helpful if you told us what you wanted your program to do :) It seemed like you wanted to go through the man and pull out the section between the NAME and the SYNOPSIS. First, a few bugs in your program (I have them listed with comments) :

# Im not sure if this pipe will open; # I'm not on a linux machine right now # so I'll just trust that this works. open (MAN, "/usr/bin/man ssh |"); while (<MAN>) { s/^\s+//g; push(@ml,$_); } # what is this loop supposed to do? # line isnt used anywhere else in the loop and # you aren't modifying @ml at all... foreach $line (@ml) { $line =~s/\n$//; $line =~s/^\n//; $line =~s/^\s+//; } for ($x=0; $x<=45; $x++) { if ($ml[$x]=~/NAME/) { while($ml[$x] !~/SYNOPSIS/) { # forgotten semicolon $nl .= $ml[$x] } } }

Heres what I did to "fix" it:

open (MAN, "/usr/bin/man ssh |"); while (<MAN>) { s/^\s+//g; push(@ml,$_); } # apply the substitutions to each element of @ml map (s/\n$//, @ml); map (s/^\n//, @ml); map (s/^\s+//, @ml); for ($x=0; $x<@ml; $x++) { if ($ml[$x] =~ /NAME/) { # new loop starting at one element past # the current, appending the current line # to $nl. Stops when SYNOPSIS is encountered for ($x++; $ml[$x] !~ /SYNOPSIS/; $x++) { $nl .= $ml[$x]; } } }

Well, there ya go. Of course, I could have completely misunderstood what you wanted your program to do... and if thats the case... I'm sure I'll get laughed at :)

Replies are listed 'Best First'.
Re (tilly) 2: script debug
by tilly (Archbishop) on Aug 19, 2001 at 07:14 UTC
    Your reply indicates a number of misunderstandings. I hope you don't mind my pointing them out as a learning exercise.
    1. If you are not sure that a pipe will open, the last thing you want to do is hope that it works. Instead do as perlstyle says and put in an informative error check. Preferably using die and showing the contents of $!.
    2. Perl style foreach loops alias each element of the array to a variable. Modifications of that variable affect the original array element. Therefore the loop is not useless.
    3. The last semi-colon in a block is optional.
    4. Do not use a map or grep if you are not using the return value. It wastes memory, runs slower, and is less intuitive. And if you really want the inline loop, just write it:
      s/foo/bar/g foreach @list;
    5. Avoid C-style for loops whenever you have the opportunity to use more Perlish foreach loops. According to several studies, the most common error in C is to have an off-by-one error in a for loop. Just loop over an array using the direct foreach and it will both execute faster and you can't make an off-by-one error.
    Now a few other general comments about the problem. First of all your removal of the hardcoded 45 is a good thing. Hard-coded numbers are a danger sign. Secondly it is a good habit to make everything run with strict.pm, which none of this code does. For short examples the benefits are not that great. Longer code is a different story. Thirdly I have to wonder whether it really makes sense to append together lines which have whitespace stripped from front and back to each other without some space to divide them. And finally, is $nl being printed? I don't see it being printed, and if it isn't, then the entire script becomes of dubious value at best.
      1. The reason I wasn't sure if it will open was because he happened to be on a unix/linux machine, while I was on a Windows machine. Therefore I can't open a man if I don't have it. I had no way of knowing whether that was going to work, so I had to create my own dummy file to test his problem.
      2. I never knew that foreach loops could do that. Sorry :(
      3. My version of windows perl will club me upside the head if I forget a semi-colon anywhere. I just assumed all versions of perl were like that.
      4. see #2
      5. see #2

      Also, I think he just wanted that snippit fixed, he probably has other stuff in his program. What, I don't know. But then who does? Finally, sorry for acting defensive, but I tend to get that way sometimes.

        I am sorry if I am putting you on the defensive. I don't mean to. I just see a number of elementary misunderstandings, and I am trying to help you get beyond them as quickly and painlessly as possible.

        As for the three foreach issues, I suspected you didn't know, which is why I explained what Perl is really doing in these three cases.

        On the semi-colon issue, I strongly doubt that what I described is wrong for your version of Perl. The following complete program should run fine on any version of Perl you are likely to run across:

        print "Hello, World\n" # Note, no semi-colon here!
        The ability to leave off a semicolon only applies to the very last semi-colon in a block. To quote my local copy of perlsyn:
        The only kind of simple statement is an expression evaluated for its side effects. Every simple statement must be terminated with a semicolon, unless it is the final statement in a block, in which case the semicolon is optional. (A semicolon is still encouraged there if the block takes up more than one line, because you may eventually add another line.) Note that there are some operators like eval {} and do {} that look like compound statements, but aren't (they're just TERMs in an expression), and thus need an explicit termination if used as the last item in a statement.
        Note that this means that if you drop a random semi-colon, you will get an error. Hence I suspect that you have simply never run into the fact that a small number of semi-colons are optional. But if you run my one-line program above and do get an error, then please follow with the command:
        perl -V
        and tell me the results so I know which version of Perl does not behave as I expect.

        For your local copy of Perl's built-in documentation (be warned that there is a lot of it, and it is slow going) you can type in:

        perldoc perl
        at a command line and work from there. (The perldoc utility comes with Perl itself and has run just fine for me on all versions of Windows where I have tried it.)

        And finally about the open issue. For testing your fix you can change the command to something that will run on your machine. But it is pretty much always a bad programming idea to interact with the system without having an error check. Sure, on your machine the program doesn't exist. But even if you are running on Linux and know full well that the line should work, the error check still belongs. There are always things that can go wrong, and that is a place where they tend to. Without that check you won't be able to easily identify and debug any of the following errors:

        1. You have a typo in your name of the command.
        2. You moved your script from one machine to another and the other does not have the command you expect, where you expect it.
        3. Your script is running in a chrooted environment and the command is not available at all to you.
        4. Your machine has run out of memory/processes/etc and is unable to run the command at all.
        5. etc...
        For these reasons and more, consistently putting in good error checks is listed in perlstyle as a more substantive style issue. (For the record, I learned how substantive when I had to get a job that took 30 minutes to run to run cleanly when it was dying without a useful error check about 20 minutes into the run. Turns out that someone with root had left the wrong permission on one file in a directory of thousands. When I left work at 1 AM I was not a happy camper...)
Re: Re: script debug
by jryan (Vicar) on Aug 19, 2001 at 00:42 UTC
    man, there was no replies when I started writing that, do I really type that slowly?