Re: how to kill background process when script exit?
by Corion (Patriarch) on Feb 19, 2011 at 21:15 UTC
|
The simple way is not to involve the shell and launch your background process via open. Then you can kill your child at program end through kill:
my $kid = open(my $fh, "launch_java.sh |")
or die "Couldn't launch 'launch_java.sh': $! / $?";
END {
if ($kid) {
kill 9 => $kid; # bang
};
};
See perlipc for other methods. | [reply] [d/l] |
|
|
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). | [reply] [d/l] [select] |
|
|
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.
| [reply] |
|
|
|
|
|
|
|
|
|
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.
| [reply] [d/l] |
|
|
|
|
$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 |");
| [reply] [d/l] [select] |
|
|
|
|
|
|
|
|
|
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.
| [reply] [d/l] |
|
|
|
|
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");
| [reply] [d/l] [select] |
|
|
#!/usr/bin/perl
my($JAVA_CLASSPATH) = @ARGV;
$java_command = "java -classpath $JAVA_CLASSPATH TextEntry";
system("$java_command 2> /dev/null &");
$kid = `ps aux | grep "$java_command" | grep -v 'grep'`;
$kid =~ s@^.*?\s+([0-9]+).*@$1@s;
END {
if ($kid) {
kill 9 => $kid; # bang
};
};
print "pid is: $pid\n\npress return to exit...";
<STDIN>
I would really like to find a more elegant way however. | [reply] [d/l] |
|
|
use strict;
my $JAVA_CLASSPATH = '...whatever';
my $java_command = "java -classpath $JAVA_CLASSPATH TextEntry";
my $kid;
defined($kid = fork()) or die "error: fork: $!";
if ($kid == 0) {
## child
# Could redirect child stdout/stderr here if desired.
# open(STDOUT, '>', 'javastdout.tmp') or die "redirect stdout: $
+!";
# open(STDERR, '>', 'javastderr.tmp') or die "redirect stderr: $
+!";
exec($java_command);
die "error: exec: $!";
}
warn "parent continues ... child pid is $kid\n";
# Could wait for child to exit using waitpid if required.
# waitpid($kid, 0);
# script continues...
END {
# Update: should first check that $kid is still alive before killi
+ng it.
# Something like: kill 0, $kid should do it (see "perldoc -f kill"
+)
if ($kid) {
kill 9 => $kid; # bang
};
};
Also, as a matter of technique, you should try "kill 15" (SIGTERM) before
resorting to "kill 9" so as to give the Java process a chance to catch
the SIGTERM signal, clean up and die more gracefully.
Update: For more elaborate sample code, using fork/exec,
"kill 15" (softer kill before resorting to "kill 9"),
"kill 0" (to check if process is still alive),
and waitpid (to reap the exited child and test its exit code),
see Timing and timing out Unix commands (especially the "kill_it" subroutine).
| [reply] [d/l] |
|
|
|
|
|
|
|
|
|
#!/usr/bin/perl
my($JAVA_CLASSPATH) = @ARGV;
$LAUNCH_JAVA = $JAVA_CLASSPATH."/launch_java.sh";
open(FH, "$LAUNCH_JAVA $JAVA_CLASSPATH |")
or die "Couldn't launch 'launch_java.sh': $! / $?";
my $kid = <FH>;
$kid =~ s@\n@@;
END {
if ($kid) {
kill 9 => $kid; # bang
};
};
print "pid: $kid\n\npress return to exit script...\n\n";
<STDIN>;
shell script (launch_java.sh):
#/bin/bash
java -classpath $1 TextEntry 2> /dev/null &
echo $!
| [reply] [d/l] [select] |
|
|
please see update on my last long post about open(), open2(), open3(). Some serious mis-conclusions were corrected. Thank you Corion & ikegami
| [reply] |
Re: how to kill background process when script exit?
by Allasso (Monk) on Feb 21, 2011 at 15:21 UTC
|
can anyone tell me why this works:
#!/usr/bin/perl
my $pid = open(my $fh, "java -classpath /Users/allasso/AWS/utility/too
+ls_additional/SC_add/java TextEntry |")
or die "Couldn't launch: $! / $?";
print "pid: $pid\n\ndoing stuff...\n\npress return to exit script...\n
+\n";
<STDIN>;
if ($pid) {
kill 9 => $pid; # bang
};
and this doesn't (hangs - can't exit script until java app is closed):
#!/usr/bin/perl
my $pid = open(my $fh, "java -classpath /Users/allasso/AWS/utility/too
+ls_additional/SC_add/java TextEntry |")
or die "Couldn't launch: $! / $?";
END {
if ($pid) {
kill 9 => $pid; # bang
};
};
print "pid: $pid\n\ndoing stuff...\n\npress return to exit script...\n
+\n";
<STDIN>;
| [reply] [d/l] [select] |
|
|
close $fh;
after the end of your program code and just before it starts to run the END block. | [reply] [d/l] |
|
|
I just observed that if I use
FH
instead of
my $fh
as the first arg to open(), it works
| [reply] [d/l] [select] |
|
|