Suppress Notice of Forked Command Being Killed
How about disown? This mostly works for me on Bash on Linux.
echo "hello"
sleep 100 &
disown
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"
Edit: Matched the poster's code better.
Suppress Notice of Forked Command Being Killed
How about disown? This mostly works for me on Bash on Linux.
echo "hello"
sleep 100 &
disown
ps ax | grep sleep | grep -v grep | awk '{ print $1 } ' | xargs kill -9
echo "bye"
Edit: Matched the poster's code better.
How to shield the kill output
The message isn't coming from either kill
or the background command, it's coming from bash when it discovers that one of its background jobs has been killed. To avoid the message, use disown
to remove it from bash's job control:
sleep 20 &
PID=$!
disown $PID
kill -9 $PID
Background Process stdout Displays After Next Command
The message is printed by bash itself, not by the kill
command. So you can't suppress it by redirecting any output in your script.
What you can do is to disable the monitor mode of job control by executing
set +m
Quote from the bash man page:
-m Monitor mode. Job control is enabled. This option is on by default for
interactive shells on systems that support it (see JOB CONTROL above). All
processes run in a separate process group. When a background job
completes, the shell prints a line containing its exit status.
With a +m
the monitor mode is disabled.
Perl - How to suppress output from a forked child process
Use the exec LIST
form to avoid surprises due to shell quoting. This also requires performing the redirection that the shell would do for you.
use 5.10.0; # //
my $pid = fork // die "$0: fork: $!"; # / fix Stack Overflow highlighting
if ($pid) {
waitpid $pid, 0 or die "$0: waitpid: $!";
warn "$0: child exited abnormally" if $?;
print ".\n"; # done!
}
else {
open STDOUT, ">", "/dev/null" or die "$0: open: $!";
open STDERR, ">&", \*STDOUT or exit 1;
exec "tar", "zcf", "/tmp/mytarball.gz", "directoryToTarBall";
exit 1;
}
Python forked processes won't die
You have to wait()
for the child-process.
Please add the following lines to get things corrected:
import sys
import os
import time
children = []
for i in range(0,3):
pid = os.fork()
if pid == -1:
continue
elif pid == 0:
# Do work...
print 'Child %d spawned' % os.getpid()
sys.exit(0)
else:
children.append(pid)
time.sleep(5)
# ADD NEXT TWO LINES:
for pid in children:
os.waitpid(pid, 0)
for pid in children:
proc_path = '/proc/%d' % pid
if not os.path.exists(proc_path):
print 'Child %d is dead' % pid
else:
print 'Child %d is alive' % pid
The parent must wait()
for the child. Please see man 2 wait
for details.
In python you can handle those things with the subprocess
module.
How to stop forking in this code
You don't indicate how many processes there may be, but no resource is unlimited and you should limit the number or you'll see a rapid degradation of performance as you reach saturation.
This is even more so when going out on the network since you may be annoying a server (and things will also stop being faster quite soon). Perhaps run up to a few tens of processes at a time?
Then one option is to limit a number of parallel downloads using Parallel::ForkManager. It has a way to return data to parent, so a child can report failure. Then its run_on_finish
method can check each batch for such a flag (of failure), and set a variable that controls the forking.
use warnings;
use strict;
use Parallel::ForkManager;
my $pm = Parallel::ForkManager->new(2); # only 2 for a managable demo
my $stop_forking;
# The sub gets 6 parameters, but only first (pid) is always defined
# The last one is what a child process may have passed
$pm->run_on_finish(
sub { $stop_forking = 1 if defined $_[-1] }
);
for my $i (0..9)
{
last if $stop_forking;
$pm->start and next; # forks
my $ret = run_job($i); # child process
# Pass data to parent under a condition
if ($ret eq 'FAIL') { $pm->finish(0, \$ret) } # child exits
else { $pm->finish }
}
$pm->wait_all_children;
sub run_job {
my ($i) = $_[0];
sleep 2;
print "Child: job $i exiting\n";
return ($i == 3 ? 'FAIL' : 1);
}
This stops forking after the batch of jobs within which $i == 3
. Add prints for diagnostics.
The "callback" run_on_finish
runs only once a whole batch completes.† The anonymous sub in it always receives 6 arguments, but only the first one, the child pid, is always defined. The last one has data possibly passed by the child, and when that happens we set the flag. A child can return data by passing a reference to finish
method. To only indicate a condition we can simply pass anything. I use \$ret
as an example of passing actual data.
See documentation for more, but this does what you ask. For yet far more see Forks::Super.
If you wish to fork as you do, I'd first put in a little sleep
there, so you don't bombard the server with too many requests. Your children can talk with the parent using socketpair. The failed child can write while all others can simply close their socket. The parent keeps checking, for example with can_read
from IO::Select. There is an example in perlipc. Since you only need children to write to the parent the pipe would suffice as well.
You can also do it with a signal. The child that fails sends (say) SIGUSR1
to the parent, which the parent traps and sets a global variable that controls further forks. This is simpler as the parent only traps that one signal and doesn't care where it comes from. See perlipc and sigtrap pragma.
You can also use a file, much like you do, which is probably simplest since here you don't care about racing issues (whether children writes overlap), but only about an empty file showing up.
However, in all these you'd also want to limit the number of parallel processes.
Finally, there are also modules that help with external commands, for example IPC::Run.
† To run the callback right as each child exits use reap_finished_children. See this post.
Killing a forked Windows process in Perl
The Forks::Super
module provides many useful facilities for handling forked processes, as well as offering a more portable interface.
This program runs notepad
to edit the program's own source file and kills the child process after five seconds. If you need to pass parameters to the command then you should specify it as an anonymous array of values like this. If you use a single string like cmd => qq<notepad "$0">
instead then you will start a copy of cmd.exe which in turn starts notepad.exe, and the kill
command will just leave notepad running as an orphan
use strict;
use warnings;
use Forks::Super;
if ( my $pid = fork({ cmd => [ 'notepad', $0 ] }) ) {
sleep 5;
Forks::Super::kill('TERM', $pid);
print "Killed\n";
}
Note that if you want to apply a timeout to the child process then you can write
my $pid = fork({ cmd => 'notepad', timeout => 600 })
Related Topics
Splitting Gzipped Logfiles Without Storing the Ungzipped Splits on Disk
Add Blank Line Between Lines from Different Groups
Linux, Where Are the Return Codes Stored of System Daemons and Other Processes
How to Get Out of 'Screen' Without Typing 'Exit'
Linux Command to Translate Domain Name to Ip
How Is It Possible That Kill -9 for a Process on Linux Has No Effect
How to Mount from Command Line Like the Nautilus Does
How to Recover After Deleting the Symbolic Link Libc.So.6
Simple Way to Convert Hh:Mm:Ss (Hours:Minutes:Seconds.Split Seconds) to Seconds
What Happens If You Mount to a Non-Empty Mount Point with Fuse
Identifying Which Linux System Library Contains a Function
Android Studio 3.0 Emulator Does Not Start
Sed Returns "Sed: Command Garbled"
How to Make Grep Print the Lines Below and Above Each Matching Line
Bash History Without Line Numbers
Linux/Bash, Using Ps -O to Get Process by Specific Name