The system using sh -c ...
to execute an external command with shell metacharacters (in your case, the >>
for output redirection, and for that matter any spaces in the command string) is documented in exec
and system
. To avoid using sh -c
and to create a single process, you can use the LIST
form of exec
:
my @cmd = ('top','-b','-d','1','-n','300','-u',$ENV{USER});
exec(@cmd);
The output redirection makes this a little tricky, but you can accomplish it by closing and reopening STDOUT
after the fork
and before the exec
:
my @cmd = ...
close STDOUT;
open STDOUT, '>>', 'logfile';
exec @cmd;
When doing output redirection, the important thing is to set up file descriptor 1 correctly, not necessarily STDOUT
. This, for example, will fail to do output redirection like you want it to.
my @cmd = ...;
close STDOUT; # close file descriptor 1
open FOO, '>/tmp/asdf'; # probably uses file descriptor 1
open STDOUT, '>>', 'logfile'; # probably uses file descriptor != 1
exec(@cmd); # probably writes output to FOO\/tmp/asdf
Alternate solution using process groups: @Chris suggests in a comment that you send a negative value to the kill
function in order to kill an entire process group. Normally the process you create with fork
has the same process group as its parent, but this will work if you set up the child process to use a new process group:
unless ($logger_pid = fork) {
use POSIX;
POSIX::setpgid($$,$$); # set child process to be in its own process group
exec($cmd);
}
...
kill -15, $logger_pid; # kill the process group with id $logger_pid