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

I can't figure out why this won't work :( # I would like to keep the same format if possible
open (MAN, "/usr/bin/man ssh |"); while (<MAN>) { s/^\s+//g; push(@ml,$_); } 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/) { $nl .= $ml[$x] } } }

Replies are listed 'Best First'.
Re: script debug
by VSarkiss (Monsignor) on Aug 19, 2001 at 00:15 UTC

    Hi, Anonymous Monk. It looks like this is a continuation to this previous question. Is it? You haven't really said what the problem is -- "this won't work" is a pretty broad problem statement -- but assuming you're the same person, working on the same problem, then maybe some suggestions are in order.

    First, you're accumulating lines in memory and not doing anything with them. If you're expecting some output, a print or something similar is necessary. Second, there's no real point collecting lines in memory if all you're going to do is copy them out verbatim. So, as a first cut, I suggest this transformation:

    open (MAN, "/usr/bin/man ssh |"); my $printing_on = 0; # If true, print what you see while (<MAN>) { s/^\s+//g; # if you like; could be omitted. if ($_ eq "NAME\n") # constant string; no regexp needed { $printing_on = 1; } elsif ($_ eq "SYNOPSIS\n") { exit; # we're done } print if $printing_on; }
    TIMTOWDI, but this is a simple way to print lines between "NAME" and "SYNOPSIS".

    I'm using the ESP::Telepathy module a lot without knowing your intentions, so I'll stop here. Please provide a little more detail about what "won't work" means, and you should get a better answer.

    HTH

      Just because I learned the flip-flop recently:
      #!/usr/bin/perl -n print if (/NAME/../SYNOPSIS/); # then: man ls | this_script.pl
      OR maybe you have other plans for the text...
      #!/usr/bin/perl $cmd = shift; open MAN, "man - $cmd |"; while (<MAN>) { $section = $_ if /^[ A-Z]+$/; push @lines, $_ if $section =~ /NAME|DESCRIPTION/; } do_something_else_with(@lines); # perhaps get rid of the page headers/footers
Re: script debug
by dws (Chancellor) on Aug 19, 2001 at 00:06 UTC
    I suspect that you're unclear on what
    $line =~s/\n$//; $line =~s/^\n//;
    will really do, and why. Take a second pass through perlre, paying particular attention to $ and its relationship to \n.

Re: script debug
by jryan (Vicar) on Aug 19, 2001 at 00:41 UTC

    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 :)

      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.

      man, there was no replies when I started writing that, do I really type that slowly?
Re: script debug
by George_Sherston (Vicar) on Aug 19, 2001 at 00:08 UTC
    Could you give an example of what you would expect to get in $nl, versus what you actually do get?

    § George Sherston