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

Hi. I'll make this short and sweet. Doing ps -ef to check for some processes running on a machine. when they're running, there's no problem. When the proc ISN'T running (which is what I want to know) I'm getting nothing. Basically doing this.
use strict; my @procs = qw|mozilla evolution|; foreach my $process(@procs) { open ( PROCS, "ps -ef |grep $process |grep -v grep|" ) or die "Cou +ldn't open procs $!"; while ( my $proc = <PROCS> ) { chomp $proc; if ( defined( $proc ) ) { print "looks okay here\n"; } else { print "couldn't find $process - you're screwed\n"; } } }
To test this, I'll change Mozilla to Gozilla in the array assignemnt at the top. Since when it loops through, running ps, grepping for Gozilla, it'll get nothing - is that not undefined in this case? In short, if I run the above, grepping for procs that don't exist, I get nothing in standard output. If I'm totally off on that, can someone point me into the direction I need to go in to check for when something WON'T be there?

Replies are listed 'Best First'.
Re: undefined question
by chromatic (Archbishop) on Jun 09, 2003 at 04:41 UTC

    If there's no output from the pipe open, there'll be nothing read from PROCS, so your loop won't execute. You could set a flag:

    my $output; while (<PROCS>) { $output++; # do something else } print "Couldn't find $process\n" unless $output;

    The a Proc::ProcessTable module might be another approach.

    Update: I forgot to mention that your loop will not execute if a line evaluating to false in boolean context is read — that may not be a problem in this case, but it's worth remembering.

      I forgot to mention that your loop will not execute if a line evaluating to false in boolean context is read

      Actually, no - if you read the perlop 'I/O Operators' entry carefully, you'll find that using <FILEHANDLE> inside a while (or for(;;)) construct is treated specially - a defined test is done for you, to avoid exactly the problem you mention...

      I case you're too lazy to look it up, I quote:

      In these loop constructs, the assigned value (whether assignment is automatic or explicit) is then tested to see whether it is defined. The defined test avoids problems where line has a string value that would be treated as false by Perl, for example a "" or a "0" with no trailing newline. If you really mean for such values to terminate the loop, they should be tested for explicitly:

      while (($_ = <STDIN>) ne '0') { ... } while (<STDIN>) { last unless $_; ... }

      In other boolean contexts, "<filehandle>" without an explicit "defined" test or comparison elicit a warning if the "use warnings" pragma or the -w command-line switch (the "$^W" variable) is in effect.

      HTH

      --
      3dan

        You're right; I just confirmed this with B::Deparse. Thanks!

        $ perl -MO=Deparse while (my $in = <STDIN>) { print $in; } ^D while (defined(my $in = <STDIN>)) { print $in; } - syntax OK
      Very nice. Quick and easy...and I woudln't have thought of it. Thanks!
Re: undefined question
by dws (Chancellor) on Jun 09, 2003 at 04:43 UTC
    If I'm totally off on that, can someone point me into the direction I need to go in to check for when something WON'T be there?

    You're not totally off. You're looking right at it. If the process doesn't exist, you'll get nothing on standard output. Here's why.

    while ( my $proc = <PROCS> ) { # if the grep filters out everything, this is a # zero-trip loop. }
    You might have better luck with something like
    my $found_one = 0; while ( my $proc = <PROCS> ) { ... $found_one = 1; } if ( $found_one ) { print "looks okay here\n"; } else { print "couldn't find $process\n"; }
    Note also that you could do both of the greps in Perl, rather than launching additional external processes.

      Thanks dws. Also informative. ONe thing though: I needed to make a small change.
      while ( my $proc = <PROCS> ) { ... $found_one = 1; } if ( $found_one ) { print "looks okay here\n"; found_one = 0; } else { print "couldn't find $process\n"; }
      W/o resetting the $found_one to 0, it would never alert me when the other processes (anything after 1) weren't running. As for the greps externally - I recall finding this in a perl tutorial many moons ago, and never learned it another way. Might you have a link that explains it internally?
        As for the greps externally - I recall finding this in a perl tutorial many moons ago, and never learned it another way. Might you have a link that explains it internally?

        You'd find that described under "regular expressions". As an example,

        open(PROCS, "ps -a | grep $process |"); while ( my $proc = <PROCS> ) { # ... }
        can be rewriten (assuming $process holds an alphanumeric string) as
        open(PROCS, "ps -a |"); while ( my $proc = <PROCS> ) { next if $proc !~ /$process/; # ... }
        Regular expressions are your friends. Learning about them pays off in many ways.