在 perl 中重定向输出时 fork exec Kill 出现问题
我在 perl 中创建了一个脚本来运行带有超时的程序。如果正在执行的程序花费的时间比超时时间长,则脚本会终止该程序并返回消息“TIMEOUT”。
该脚本运行得很好,直到我决定重定向执行程序的输出。
当 stdout 和 stderr 被重定向时,脚本执行的程序不会被终止,因为它的 pid 与我从 fork 获得的 pid 不同。
看起来 perl 执行的 shell 在重定向的情况下执行我的程序。
我希望有输出重定向,但仍然能够在超时的情况下终止程序。
关于我如何做到这一点有什么想法吗?
我的脚本的简化代码是:
#!/usr/bin/perl
use strict;
use warnings;
use POSIX ":sys_wait_h";
my $timeout = 5;
my $cmd = "very_long_program 1>&2 > out.txt";
my $pid = fork();
if( $pid == 0 )
{
exec($cmd) or print STDERR "Couldn't exec '$cmd': $!";
exit(2);
}
my $time = 0;
my $kid = waitpid($pid, WNOHANG);
while ( $kid == 0 )
{
sleep(1);
$time ++;
$kid = waitpid($pid, WNOHANG);
print "Waited $time sec, result $kid\n";
if ($timeout > 0 && $time > $timeout)
{
print "TIMEOUT!\n";
#Kill process
kill 9, $pid;
exit(3);
}
}
if ( $kid == -1)
{
print "Process did not exist\n";
exit(4);
}
print "Process exited with return code $?\n";
exit($?);
感谢您的帮助。
I created a script in perl to run programs with a timeout. If the program being executed takes longer then the timeout than the script kills this program and returns the message "TIMEOUT".
The script worked quite well until I decided to redirect the output of the executed program.
When the stdout and stderr are being redirected, the program executed by the script is not being killed because it has a pid different than the one I got from fork.
It seems perl executes a shell that executes my program in the case of redirection.
I would like to have the output redirection but still be able to kill the program in the case of a timeout.
Any ideas on how I could do that?
A simplified code of my script is:
#!/usr/bin/perl
use strict;
use warnings;
use POSIX ":sys_wait_h";
my $timeout = 5;
my $cmd = "very_long_program 1>&2 > out.txt";
my $pid = fork();
if( $pid == 0 )
{
exec($cmd) or print STDERR "Couldn't exec '$cmd': $!";
exit(2);
}
my $time = 0;
my $kid = waitpid($pid, WNOHANG);
while ( $kid == 0 )
{
sleep(1);
$time ++;
$kid = waitpid($pid, WNOHANG);
print "Waited $time sec, result $kid\n";
if ($timeout > 0 && $time > $timeout)
{
print "TIMEOUT!\n";
#Kill process
kill 9, $pid;
exit(3);
}
}
if ( $kid == -1)
{
print "Process did not exist\n";
exit(4);
}
print "Process exited with return code $?\n";
exit($?);
Thanks for any help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试将
$cmd
从 更改为
exec
将告诉由 perl 生成的 shell 将其自身替换为very_long_program,而不是作为子进程运行very_long_program。(在这种情况下,perl 生成 shell 的原因是因为
$cmd
包含重定向字符 - 而 perl 本身不知道如何处理它们。解决该问题的另一种方法是进行重定向在 Perl 本身中,在fork()
之后但在调用exec()
之前 - 但这有点棘手,所以首先尝试exec
解决方法!)Try changing
$cmd
fromto
The
exec
will tell the shell that gets spawned by perl to replace itself with very_long_program, rather than running very_long_program as a child.(The reason perl spawns a shell in this case is because
$cmd
contains the redirect characters - and perl doesn't know how to handle them itself. An alternative way of solving the problem is to do the redirection in perl itself after thefork()
but prior to callingexec()
- but that's slightly trickier, so try theexec
workaround first!)另一种方法是在 fork 之后重定向 STDOUT 和 STDERR 并在不重定向的情况下运行命令:
An alternative is to redirect STDOUT and STDERR after the fork and run the command without the redirection: