此问题与之前的问题有关: perl run background job and force job to finish?
我以为我有一个脚本可以通过kill 15, $logger_pid
成功杀死我的后台工作,但事实证明该命令会创建两个工作。请参阅以下详细信息:
#!/usr/bin/perl
use strict;
# Do a background $USER top every minute
my $cmd = "top -b -d 1 -n 300 -u $ENV{USER} >> logfile";
$SIG{CHLD}="IGNORE"; my $logger_pid;
unless ($logger_pid=fork) { exec($cmd); }
# This actually creates two jobs with consecutive PIDs
# $USER 5609 0.0 0.0 63820 1072 pts/9 S 09:42 0:00 sh -c top -b -d 1 -n 300 -u $USER >> logfile
# $USER 5610 0.6 0.0 10860 1216 pts/9 S 09:42 0:00 top -b -d 1 -n 300 -u $USER
# Do something for a while
foreach my $count (1..5) { print "$count\n"; sleep 1; }
# I thought this first kill command was enough
kill 15, $logger_pid;
# This line is needed to kill the child job
kill 15, ($logger_pid+1);
1;
有人可以告诉我为什么我需要第二个kill 15, ($logger-pid+1)
来实际杀死后台工作吗?有没有办法用一个kill
语句来做到这一点?
答案 0 :(得分:2)
使用sh -c ...
执行带有外部元字符的外部命令的系统(在您的情况下,>>
用于输出重定向,以及命令字符串中的任何空格)记录在{{ 1}}和exec
。为避免使用system
并创建单个流程,您可以使用sh -c
形式的LIST
:
exec
输出重定向使这有点棘手,但您可以通过在my @cmd = ('top','-b','-d','1','-n','300','-u',$ENV{USER});
exec(@cmd);
之后和STDOUT
之前关闭并重新打开fork
来完成此操作:
exec
进行输出重定向时,重要的是正确设置文件描述符1,不一定是my @cmd = ...
close STDOUT;
open STDOUT, '>>', 'logfile';
exec @cmd;
。例如,这将无法像您希望的那样进行输出重定向。
STDOUT
使用流程组的替代解决方案: @Chris在评论中建议您向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
函数发送负值,以便终止整个流程组。通常,使用kill
创建的流程与其父流程具有相同的流程组,但如果您将子流程设置为使用新流程组,则此工作将起作用:
fork