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

I made a code in Perl that (please don't laugh) takes a ping log out from a file, and analyze it, counting lost pings, ping time, etc, and make a little ASCII Graphic, and all.

It's not a very useful software, if I tell you that I use windows, and that is thousands of free applications for things like that on websites, but doesn't matter, I made it for educational reasons, to learn a little more.

My problem in this moment is to LOG the pings.

How I do it? I execute a separated command line ping -t perlmonks.org >ping.log, and then in my little code, I analyze this file ping.log.

As far as I remember in my lazy attempts to read the Camel Book, there are two ways to execute and external command in Perl: system, and exec.

exec, execute, and dies.

system, executes, waits until the procedure is finished and then continues the program.

In this case, NONE works. I'd need to have something that could execute something and forget about it, is there something in Perl to do that?


-------
[]'s
FiReWaLL
The mand with the red hat.

Replies are listed 'Best First'.
Re: Executing independet commands in PERL
by dvergin (Monsignor) on Mar 04, 2001 at 19:26 UTC
    Perhaps   ping -t perlmonks.org > ping.log   isn't working because the -t option goes forever until you stop it. So the the file ping.log is never closed. (You might take a look at the -n option.)

    You don't make clear if you *need* a log file or if that is just your strategy for accomplishing your analysis.

    If you are open to other ways of grabbing the data, you might skip redirecting the results to a file. Consider using back-ticks or qx(...) and then just wait for each run before proceeding. Here's a brief example with a generous sprinkling of intermediate variables for clarity.

    #!/usr/bin/perl5 -w use strict; my ($avg_time, $raw_data, @times, $time_count, $total_time); my $repeats = 5; my $addr = 'www.perlmonks.net'; for (my $i = 1; $i <= $repeats; $i++) { $raw_data = `ping $addr`; # NOTE back-ticks # Now do something interesting. We'll just... @times = $raw_data =~ /time=(\d+)/g; $total_time = 0; $time_count = 0; for (@times) { $total_time += $_; $time_count++; } $avg_time = $total_time / $time_count; print "$i. Average time: ${avg_time}ms\n"; }
    Which produces:
    1. Average time: 61.25ms 2. Average time: 61.75ms 3. Average time: 60.75ms 4. Average time: 62ms 5. Average time: 62.25ms
    You could, of course, just collect your data in the larger for loop and then do your analysis on the whole thing after you have collected as many ping responses as you need. Just make sure you don't set the data gathering processes to run forever.   ;-)

      It solves the ping problem, but doesn't solve "executing another program WITHOUT stoping mine".

      This ping thing came into my mind, because where I'm living now I have a BAD ISDN connection that needs to be controlled, so I started opening a window and ping perlmonks -t and just look at it.

      After, as a good programmer, I saw so many data passing in the screen and the only thing that I could think about was "ANALYSE!!!!!", so I changed the ping -t into a log file, and started to make a little program that got a little bit bigger, and bigger, and finally, I wanted to put all toghether, and then... the rest you know...

      So my main question is not how to ping and log, or how to ping and analyse, is how to execute something else without worying about it after started...

      I got a lot of answers that worked below like as for example system "open ping -t perlmonks.org >ping.log".

      That one worked perfeclty for what I needed, like that I can open a text editor, I can open a Browser, and in windows, I can say the file that I want to open, or the site (in the case of the browser)...


      -------
      []'s
      FiReWaLL
      The only thing you regret in life, is the risk you don't take.

Re: Executing independet commands in PERL
by AgentM (Curate) on Mar 05, 2001 at 00:41 UTC
    It seems that you have more than enough help posted above, so let me just quickly make sure that you understand the differences between fork, exec, and system. They are very often confusing. Your analysis of exec is not entirely correct.
    • exec replaces the current process binary with a new executable binary. Hence, if you ran a perl script and called exec in the same process, you would lose anything that you wrote in that perl script (with some exceptions which are not relevant under Winduz).
    • fork will create a new process and populate it with instructions or a new process, hence giving birth to
    • system which is essentially a fork and exec. The process creates a child process and populates it with the shell command. It then proceeds to waitpid on that system call.

    AgentM Systems nor Nasca Enterprises nor Bone::Easy nor Macperl is responsible for the comments made by AgentM. Remember, you can build any logical system with NOR.
Re: Executing independet commands in PERL
by ColtsFoot (Chaplain) on Mar 04, 2001 at 16:04 UTC
    You are going to need to fork a process that performs the ping and then in the parent you should be able to examine the log file.
    If you are using ActiveState perl 5.6 then Take a look at this
    Hope this helps

      Of course, it's still to note that the fork() implementation of ActiveState Perl, while amazing, does not yet work correctly, as the Win32 API dosen't support fork() in a native way. It's easy to break forking programs by passing sockets to your children.

      If you don't need to pass information between your parent and child process, it might be easier to use system() calls to start new instances of the child script(s)...

Re: Executing independet commands in PERL
by btrott (Parson) on Mar 05, 2001 at 00:13 UTC
    For information on starting up another process and letting it run independently of your own, check out perlipc.

    But you may want to try and get rid of the external program altogether and use Net::Ping. Then you have control over the entire process.

    An example from the docs:

    $p = Net::Ping->new(); print "$host is alive.\n" if $p->ping($host); $p->close();
      Net::Ping doesn't use ICMP, but UDP/TCP to connect to the echo port of a machine. I tried using it, but found out you couldn't use ICMP and most machines don't have their echo port enabled for obvious reasons... In my current version I use Open3. The options for ping probably don't apply to Windows ping. I use FreeBSD 4.2 here.
      #!/usr/local/bin/perl5 -w use IPC::Open3; use Symbol; # .ping contains hostnames, each on a seperate line. open(HOSTS, "<.ping") || die("Can't open hostsfile! ($!)\n"); @hosts = <HOSTS>; close(HOSTS); %PING = (); %STATUS = ( -1 => "Host not found", 0 => "Not done", 1 => "Host is alive", 2 => "No reply from host", ); foreach $host (@hosts) { chomp $host; $WTR = gensym(); $RDR = gensym(); $ERR = gensym(); $PING{$host}{'PID'} = open3($WTR, $RDR, $ERR, "/sbin/ping -n -q -c 1 + $host"); close($WTR); while (<$RDR>) { $PING{$host}{'OUT'} .= $_; } while (<$ERR>) { $PING{$host}{'ERR'} .= $_; } $PING{$host}{'STATUS'} = 0; } foreach $host (keys %PING) { if(defined($PING{$host}{'ERR'})) { if($PING{$host}{'ERR'} =~ /Unknown host/) { $PING{$host}{'STATUS'} = -1; next; } } if($PING{$host}{'OUT'} =~ /.*, (.*) packets received.*/) { $PING{$host}{'STATUS'} = ($1 == 1?1:2); } } foreach $host (keys %PING) { printf "%-30s %s\n", $host, $STATUS{$PING{$host}{'STATUS'}}; }
        According to the docs it supports icmp:
        $p = Net::Ping->new("icmp"); foreach $host (@host_array) { print "$host is "; print "NOT " unless $p->ping($host, 2); print "reachable.\n"; sleep(1); } $p->close();
Re: Executing independet commands in PERL
by the_slycer (Chaplain) on Mar 04, 2001 at 22:19 UTC
    With Windows, if you don't read results from the program you want to execute into a variable or something, then the easiest way is to use the "start" command. So, something like
    system ("start path\to\command");
    Normally works quite well. The nice thing about this is that your code only waits for "start" to finish (which occurs almost instantly)
Re: Executing independet commands in PERL
by Anonymous Monk on Mar 04, 2001 at 23:28 UTC
    Try something like @log=qx/ping -t perlmonks.org/. Haven't tried it, but I think the qx operator is what you need, it returns the output of an external command. See man perlop, too.
      For the record, qx/.../  is the same as back-ticks.

      Update: Merlyn is correct, of course in his post following this one. I was just trying to make a friendly connection regarding function. But the effect of different delimiters has a bearing on function. Back-peddling as fast as possible... Umm... let's just call them close relatives...

        Almost. qx`...` would be the same as backticks. qx/.../ would have a slash for a delimiter, and hence require a different backslashing strategy. And qx'...' would have single-quote for a delimiter and not support variable interpolation or backslash escaping.

        -- Randal L. Schwartz, Perl hacker

Re: Executing independent commands in PERL
by swr (Initiate) on Mar 05, 2001 at 16:04 UTC
    Is there some reason nobody has suggested open(PING, "ping -t perlmonks.org|") ? Or does that not work in the windows perl? If recording the logfile is important, you could always write the output to the logfile from perl as the data is read in.