in reply to Re: how to kill background process when script exit?
in thread how to kill background process when script exit?

Am I missing a big pink elephant here?

that does not seem to launch the process in the background though. I want to launch the java app, then continue on with my script (also, the pid isn't returned until I quit the java app - not real helpful). It seems that an '&' is necessary here, no?

But anyway, I had already tried other things using open() as well, but I couldn't get them to work:

$kid = open (FH, "java JavaApp | &"); print $kid;

(gives "no such file or directory" message, $kid not returned until java app is quit)

$kid = open (FH, "java JavaApp & |"); print $kid;

(causes my script to hang, $kid not returned at all)

for some reason, if I redirect the stderr to /dev/null:

$kid = open (FH, "java JavaApp 2> /dev/null & |"); print $kid;

the app DOES run in the background, $kid is returned immediately, HOWEVER, the app doesn't quit when I end the script. If I take the number returned in $kid (eg, 1001), and manually try to kill the process with it I get:

kill 1001 -bash: kill: (1001) - No such process

Also tried:

`java JavaApp &`

(gives "no such file or directory" message)

??????

I have found lots of stuff on the net on how to start a background process in perl, but nothing on how to kill one (in a perl script).

Replies are listed 'Best First'.
Re^3: how to kill background process when script exit?
by roboticus (Chancellor) on Feb 19, 2011 at 22:56 UTC

    Alasso:

    I bet it's those ampersands that are getting in your way. The open statement, when given a string ending with a vertical bar tells perl to try to run the program in the background and redirect the standard output to the opened file stream. So in the first case, it fails because the string didn't end with a vertical bar, so it tried to use it as a filename. The second and third fail because when the shell starts, it then tries to open another process in the background. So you lose control of the child of the child.

    Give it a go without the ampersand, and let us know if that doesn't fix it.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      robiticus

      okay, here's another example, with no ampersand. In this case, the app is (apparently) running in the background, because my script continues (prints out "pid: 1234"). HOWEVER, I can't exit the script until I exit the java app.

      #!/usr/bin/perl my($JAVA_CLASSPATH) = @ARGV; my $kid = open(my $fh, "java -classpath $JAVA_CLASSPATH TextEntry 2> / +dev/null |") or die "Couldn't launch 'launch_java.sh': $! / $?"; END { if ($kid) { kill 9 => $kid; # bang }; }; print "pid: $kid\n\npress return to exit script...\n\n"; <STDIN>;

        Alasso:

        Hmmm ... I'm playing with it to see what I can determine. In about 10 minutes, I've had no luck. I'll report back if I find something.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

        Update: Well, I've tried a couple things, but I've not found anything useful.

        I'm confused now. I thought you wanted to kill the child program at the end of your script?

        Now you say you don't want to kill the child program. Which is it?

Re^3: how to kill background process when script exit?
by ikegami (Patriarch) on Feb 19, 2011 at 23:59 UTC

    The problem is that $kid is the pid of the shell you launched (since you provided a shell command), and it exits as soon as it launches java. You could avoid the shell.

    use IPC::Open3 qw( open3 ); { open(local *CHILD_STDIN, '<', '/dev/null') or die; open(local *CHILD_STDERR, '>', '/dev/null') or die; local *FROM_CHILD; my $kid = open3('<CHILD_STDIN', \*FROM_CHILD, '>CHILD_STDERR', 'java', 'JavaApp' ); ... }

    Higher-level solutions possible using IPC::Run3 and IPC::Run.

      I just realized that what I had "discovered" is exactly what you were trying to tell me. Somehow I just wasn't seeing it. (wouldn't be the first time).
Re^3: how to kill background process when script exit?
by ikegami (Patriarch) on Feb 20, 2011 at 05:20 UTC

    First,

    $kid = open (FH, "java JavaApp 2> /dev/null & |");

    should be

    $kid = open (FH, "java JavaApp 2> /dev/null |");

    It makes no sense to use "&" there. Removing it might even solve your problem. $kid would still refer to the shell, but killing the shell might kill its children too. Killing the negative of the shell's PID has an even greater chance of working. But why keep the shell around?

    $kid = open (FH, "exec java JavaApp 2> /dev/null |");

      ikegami,

      I agree that it makes no sense to use it there, I was trying stuff out of desparation :-). It was interesting however the results that it did have, even though not what I ultimately want.

      It seems the consensus is that using open() to launch the app should run it in the background, but it just does not seem to be what I experience. My code (in the perl script) does not continue to execute until the child process has quit.

        Sorry, but you are mistaken.
        $ perl -E' say "".localtime; open my $fh, q{perl -e sleep |}; say "".localtime; ' Sun Feb 20 13:25:05 2011 Sun Feb 20 13:25:05 2011 [hung waiting for child to exit]

        or how about

        $ perl -E' open my $fh, q{perl -E'\''sleep 1; say STDERR "C"'\'' |}; say "P"; ' P C
      I just caught your third example there - and it works also:
      $kid = open (FH, "exec java JavaApp 2> /dev/null |");
      So then instead of the shell running the app, the shell becomes the app, so the pid is the same. clever.
Re^3: how to kill background process when script exit?
by Corion (Patriarch) on Feb 19, 2011 at 22:47 UTC

    Do all the redirection in the shell script and do not launch it in the background. The open(my $fh, "... |") will launch the script and also make it available for reading.

    As an alternative, just write the process id to a file and then exec the Java process from the shell script. If you use exec, the PID will remain the same. Then read that pid from Perl and kill that other process.

      Corion:

      "Do all the redirection in the shell script and do not launch it in the background. The open(my $fh, "... |") will launch the script and also make it available for reading."

      when I do this, I get basically the same results as opening the java app directly - my script continues, but I can't exit the script until I close the java app.

      also tried using the ampersand in the shell script, but then it doesn't kill the java app when I exit.

      I'm really trying, guys, maybe I'm missing something stupid.

Re^3: how to kill background process when script exit?
by Allasso (Monk) on Feb 20, 2011 at 18:34 UTC

    I found that redirecting output causes the process to be run in a shell (this is un-explicitly mentioned in some or all of the open[ 23]() docs), thus the pid returned is the pid of the shell process, not my command.

    ps aux | grep java | grep -v grep

    Revealed that it was killing the shell, but killing the shell did not stop the process from running.

    Corion was correct.

    ikegami tried to tell me about the shell thing, but I didn't catch what he was saying.

    here are some examples using open(), open2() and open3() and the results I observed:

    use IPC::Open2 qw( open2 ); use IPC::Open3 qw( open3 ); # this works: my $kid = open(FH1, "java -classpath $PATH TextEntry"); my $kid = open2(FH1, FH2, "java -classpath $PATH TextEntry"); my $kid = open3(FH1, FH2, FH3, "java -classpath $PATH TextEntry"); # however, when I try to suppress stderr, # it doesn't work because of the redirection, # and the process is launched it in a shell; # $kid is the pid of the shell: my $kid = open(FH1, "java -classpath $PATH TextEntry 2> /dev/null"); my $kid = open2(FH1, FH2, "java -classpath $PATH TextEntry 2> /dev/null"); # no problem, open3() will capture STDERR, taking # care of the redirection: my $kid = open3(FH1, FH2, FH3, "java -classpath $PATH TextEntry"); # however, the use IPC::Open2() docs # (to which IPC::Open3() is compared to) # indicates that the above form would be run in a shell, # so it may be safer to do this: my $kid = open3(FH1, FH2, FH3, "java", "-classpath", "$PATH", "TextEntry"); # but there is a way to capture the child output # using open() and still kill it when parent exits: # exec the command from the shell, thus # $kid = pid of shell = pid of the command # suggested by ikegami: my $kid = open(FH1, "exec java -classpath $PATH TextEntry 2> /dev/null");