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

Hello monks,

I have a bunch of polished Perl scripts and Win32 batch files I use for regular sysadmin tasks. I launch these manually from a command prompt, and they handle things like simple backups, file locating, log printouts. These scripts require no user intervention whatsoever, although some take a few parameters. They generally log output to a file, or e-mail me results.

I'd like to write a launcher for these scripts. What I have in mind is a script that loops eternally on my workstation, waiting for trigger from me or someone else. The trigger might be the appearance of a certain file, or maybe a signal from another process. When a trigger is pulled, the launcher will run the appropriate script, and immediately continue waiting for new triggers.

Conceptually, I'm stuck on the best way to actually launch the scripts. I've looked at fork, open, system, exec, backticks, and a few modules, but they either don't do quite what I need, or they are far too complex for my purposes. I just need to launch a script (or batch or exe) and continue. I don't need to capture output; I don't want to wait for the script to finish execution; I don't care about the success or failure of the process; I don't need any communication with the process after it launches.

What's a simple way of accomplishing this? Thanks!

Replies are listed 'Best First'.
Re: Launching a process
by BrowserUk (Patriarch) on Jun 13, 2003 at 01:33 UTC

    The simplest way is to use system and the win32 start command with /b (background) option.

    system 'start /b perl script 1>nul 2>&1';

    The redirection isn't necessary if your script produce no output, but it doesn't harm. It would probably better to redirect to a file somewhere so you get a log of any runtime errors or warnings produced. Without the redirection any output from all the processes will be logged to the same console which could become a bit confusing.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      Thanks! I couldn't figure out how to make system stop waiting for the script to finish, but start /b seems to do the trick! One question -- I understand 1>nul, but what does the 2>&1 do?

        For most POSIX-wannabe platforms, STDIN is handle 0, STDOUT is handle 1, STDERR is handle 2.

        • "command >foo" is the same as "command 1>foo".
        • "command 2>foo" redirects errors, not output.
        • "command 2>&1" ties error output to wherever plain output is going.
        Some command shells have different syntax for these, and some are picky about the order ("command foo 2>&1 1>foo" may act differently).

        --
        [ e d @ h a l l e y . c c ]

        2>&1 just says "redirect handle 2 (STDERR by convention) to the same place as handle 1 (STDOUT).

        If it was preceded by 1>my.log, then output from both handles would end up in same file. In the case of redirection to nul, this is effectively the same as doing 1>nul 2>nul, but if you tried to do 1>my.log 2>my.log you will get

        The process cannot access the file because it is being used by another process.

        under win32. When the file is opened for the first handle, it is opened for exclusive access, so when the the attempt is made to open it for the second handle you get this error.

        Order is also important. If you try  2>&1 1>nul, then you are asking for handle 2 to be redirected to the same the as handle 1, which is the terminal by default (and the same place as the default for handle 2), you then redirect handle 1 to the nul device, but this does not also redirect handle 2, so output to STDERR wil still end up on the terminal and only the output to STDOUT will get bit-bucketed.


        Examine what is said, not who speaks.
        "Efficiency is intelligent laziness." -David Dunham
        "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


Re: Launching a process
by meredith (Friar) on Jun 13, 2003 at 00:29 UTC
    I think system is what you're looking for -- what's the problem with it? If you set $SIG{CHLD} = 'IGNORE' then you can pretty much forget about them. Actually I'm not sure if SIGCHLD is even simulated on Win32 (sounds tricky). The only caveat about exec is shared IO handles, but it sounds like that doesn't matter. (Personally, I'd just reopen STDOUT and STDERR to a log file and let it fly).

    If you really are against using a core function, look at Win32::Process, you can create a process, then toss the object (or use in a void context).

    HTH

    Update: I'm a putz. s/exec/system/ =P

    Update2: Oh yeah, no 'foo &' for BG in Win32! right. How about this: instead of system, do a fork, then make the child exec. Or, if you fork, then system, you can do a finish-up task, such as a notification. Anyone else want to comment? :>

    mhoward - at - hattmoward.org
Re: Launching a process
by EvdB (Deacon) on Jun 13, 2003 at 07:25 UTC
    Hello, I use the following bit of code to watch a file and to run a commandline option when it changes.
    #!/usr/local/bin/perl -w # Usage: file-watch.pl file_to_watch interval commands_to_run # $Id: file-watch.pl,v 1.1.1.1 2003/06/12 12:20:13 evdb Exp $ use strict; my $file = shift @ARGV; my $SLEEP = shift @ARGV; my @CMD = @ARGV; die "Could not find the file $file.\n" unless -e $file; my $last_mod = (stat($file))[9]; my $self_mod = (stat($0))[9]; while (1) { my $curr_mod = (stat($file))[9]; if ( $curr_mod > $last_mod ) { $last_mod = $curr_mod; system @CMD; } else { sleep $SLEEP; } }

    Create a file test.txt and then try file-watch.pl test.txt 3 'echo It Changed!'. When you touch the test file you will see the message. Greate for watching latex files that you are editing, compiling them, turning the dvi into ps and then sending HUP to gv to refresh the display.

    file-watch.pl file.tex 2 "latex file.tex && latex file.tex && dvips -o file.ps file.dvi && killall -HUP gv"

    You will of course have to add something else to the command line. You could also use cron if the scripts should run at a certain time.

    --tidiness is the memory loss of environmental mnemonics

Re: Launching a process
by meredith (Friar) on Jun 13, 2003 at 11:48 UTC
    Oh also, if you are going to use files as triggers, you might want to check out Win32::ChangeNotify. Windows has an event-based system for watching files, and it definitely saves on the loop/sleep cycles. That way, you just call wait and let it block until a change. Handy stuff -- those programmers at MS aren't _complete_ losers ;)

    mhoward - at - hattmoward.org