当 运行 进程不是子进程时,如何在 perl 中等待 运行 进程完成?
How to wait for running process to complete in perl when running process is not child process?
我正在浏览一个正在使用的 Perl 脚本
waitpid($pid, 0)
等待当前进程完成。
但是 print
在这个 waitpid
之后写的语句在过程完成之前打印它。
我想知道为什么 waitpid
不先等待进程完成。
另外,运行 进程的控制在不同的模块下,不是这个 perl 脚本的一部分。只能访问进程的 pid 和名称。我无法更改调用该过程的模块中的任何内容。
Waits for a particular child process to terminate and returns the pid
of the deceased process, or -1 if there is no such child process.
快速测试:
my $pid = open my $fh,"-|","sleep 3";
print waitpid(28779,0); # Some other process
print waitpid($pid,0);
28779 是当前 运行 的另一个进程(从 ps axu
中随机抽取一个)。输出:
-1
4088
您不能使用 waitpid
等待不是当前进程子进程的进程。
The kill
command 可以检查 PID 当前是否为 运行:
print kill(0,28779);
输出:
1
您仍然需要轮询(睡眠循环)让 pid 消失。还要记住,受监视的进程可能会退出,并且新的进程可能会在您下一次检查之前重用相同的 PID(不太可能,但有可能)。
注意 一个 simple-minded one-liner 和 kill 0, $pid
在最后,评论。
我们需要检测外部程序是否已完成,但该脚本并未启动该程序。该问题询问有关使用 waitpid
的问题。复制我的早期评论:
You cannot. You can only wait on a child process. See perldoc wait
(or waitpid
, it's the same), first sentence.
wait
和 waitpid
等待发送到脚本的关于其 child(ren) 命运的信号。脚本没有理由接收有关它未启动的进程的此类信号。
我们知道进程的 ID 和名称。它的PID可以用来轮询是否是运行ning。单独使用 pid
并不完全可靠,因为在我们的检查之间,进程可以完成并且随机分配一个新的相同 pid
。我们可以使用程序的名称来加强这一点。
在 Linux 系统上,可以通过使用(许多)ps
选项获取有关进程的信息。其中任何一个 returns 程序的完整调用
ps --no-headers -o cmd PID
ps --no-headers -p PID -o cmd
返回的字符串可能以解释程序的路径(例如,对于 Perl 脚本)开头,后跟程序的全名。版本 ps -p PID -o comm=
returns 只有程序的名称,但我发现它可能会在连字符(如果有)上打断那个词,导致名称不完整。这可能需要在某些系统上进行调整,请咨询您的 man ps
。如果没有给定 PID 的进程,我们什么也得不到。
然后我们可以检查 PID,如果找到,检查该 PID 的名称是否与程序匹配。该程序的名称是已知的,我们可以对其进行硬编码。但是,它仍然由脚本在启动时使用上面的 ps
命令获取,以避免歧义。 (然后它也是相同的格式以供以后比较。)这本身会根据已知名称进行检查,因为不能保证脚本执行时的 PID 确实是预期程序。
use warnings;
use strict;
# For testing. Retrieve your PID as appropriate for real use
my $ext_pid = $ARGV[0] || $$;
my $cmd_get_name = "ps --no-headers -o cmd $ext_pid";
# For testing. Replace 'sleep' by your program name for real use
my $known_prog_name = 'sleep';
# Get the name of the program with PID
my $prog_name = qx($cmd_get_name);
# Test against the known name, exit if there is a mismatch
if ($prog_name !~ $known_prog_name) {
warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!";
exit;
}
my $name;
while ( $name = qx($cmd_get_name) and $name =~ /$prog_name/ )
{
print "Sleeping 1 sec ... \n";
sleep 1;
}
# regex above may need slight adjustment, depending on format of ps return
通过上面的 qx()
(反引号运算符)收到的命令输出包含换行符。如果这被证明是脚本执行的问题,则可以对其进行 chomp
编辑,这需要稍作调整。剩下的漏洞是 那个 程序可能已经完成并在检查之间重新启动,并且具有相同的 PID。
这将由 运行ning 在 shell
中进行测试
sleep 30 &
script.pl `ps aux | egrep '[s]leep'`
egrep
是 grep -E
。 `ps ...`
的输出包含多个单词。这些作为命令行参数传递给我们的脚本,它使用第一个作为 PID。如果它有问题 运行 首先 ps
过滤然后手动输入 PID 作为脚本的输入参数。上面的30秒sleep
是为了给命令行足够的时间做这一切。
可以通过$name
匹配一个hard-coded$prog_name
来简化代码,如果程序名足够唯一并且不会改变的话。
hard-coded 名称 是上面使用的 ,但用于检查,如果不匹配它会生成警告。 (如果我们仅依赖于硬编码,那么如果它不匹配,我们将无法发出警告,因为那是代码操作的一部分。)
如果进程与脚本属于同一用户,则可以使用 kill 0, $pid
,如
while ( kill 0, $ext_pid ) { sleep 1 }
然后您要么必须再次调用以检查名称,要么满足于 $pid
代表的实际过程中出现错误的(小)可能性。
模块 Proc::ProcessTable
可用于其中的大部分内容
我正在浏览一个正在使用的 Perl 脚本
waitpid($pid, 0)
等待当前进程完成。
但是 print
在这个 waitpid
之后写的语句在过程完成之前打印它。
我想知道为什么 waitpid
不先等待进程完成。
另外,运行 进程的控制在不同的模块下,不是这个 perl 脚本的一部分。只能访问进程的 pid 和名称。我无法更改调用该过程的模块中的任何内容。
Waits for a particular child process to terminate and returns the pid of the deceased process, or -1 if there is no such child process.
快速测试:
my $pid = open my $fh,"-|","sleep 3";
print waitpid(28779,0); # Some other process
print waitpid($pid,0);
28779 是当前 运行 的另一个进程(从 ps axu
中随机抽取一个)。输出:
-1
4088
您不能使用 waitpid
等待不是当前进程子进程的进程。
The kill
command 可以检查 PID 当前是否为 运行:
print kill(0,28779);
输出:
1
您仍然需要轮询(睡眠循环)让 pid 消失。还要记住,受监视的进程可能会退出,并且新的进程可能会在您下一次检查之前重用相同的 PID(不太可能,但有可能)。
注意 一个 simple-minded one-liner 和 kill 0, $pid
在最后,评论。
我们需要检测外部程序是否已完成,但该脚本并未启动该程序。该问题询问有关使用 waitpid
的问题。复制我的早期评论:
You cannot. You can only wait on a child process. See
perldoc wait
(orwaitpid
, it's the same), first sentence.
wait
和 waitpid
等待发送到脚本的关于其 child(ren) 命运的信号。脚本没有理由接收有关它未启动的进程的此类信号。
我们知道进程的 ID 和名称。它的PID可以用来轮询是否是运行ning。单独使用 pid
并不完全可靠,因为在我们的检查之间,进程可以完成并且随机分配一个新的相同 pid
。我们可以使用程序的名称来加强这一点。
在 Linux 系统上,可以通过使用(许多)ps
选项获取有关进程的信息。其中任何一个 returns 程序的完整调用
ps --no-headers -o cmd PID ps --no-headers -p PID -o cmd
返回的字符串可能以解释程序的路径(例如,对于 Perl 脚本)开头,后跟程序的全名。版本 ps -p PID -o comm=
returns 只有程序的名称,但我发现它可能会在连字符(如果有)上打断那个词,导致名称不完整。这可能需要在某些系统上进行调整,请咨询您的 man ps
。如果没有给定 PID 的进程,我们什么也得不到。
然后我们可以检查 PID,如果找到,检查该 PID 的名称是否与程序匹配。该程序的名称是已知的,我们可以对其进行硬编码。但是,它仍然由脚本在启动时使用上面的 ps
命令获取,以避免歧义。 (然后它也是相同的格式以供以后比较。)这本身会根据已知名称进行检查,因为不能保证脚本执行时的 PID 确实是预期程序。
use warnings;
use strict;
# For testing. Retrieve your PID as appropriate for real use
my $ext_pid = $ARGV[0] || $$;
my $cmd_get_name = "ps --no-headers -o cmd $ext_pid";
# For testing. Replace 'sleep' by your program name for real use
my $known_prog_name = 'sleep';
# Get the name of the program with PID
my $prog_name = qx($cmd_get_name);
# Test against the known name, exit if there is a mismatch
if ($prog_name !~ $known_prog_name) {
warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!";
exit;
}
my $name;
while ( $name = qx($cmd_get_name) and $name =~ /$prog_name/ )
{
print "Sleeping 1 sec ... \n";
sleep 1;
}
# regex above may need slight adjustment, depending on format of ps return
通过上面的 qx()
(反引号运算符)收到的命令输出包含换行符。如果这被证明是脚本执行的问题,则可以对其进行 chomp
编辑,这需要稍作调整。剩下的漏洞是 那个 程序可能已经完成并在检查之间重新启动,并且具有相同的 PID。
这将由 运行ning 在 shell
中进行测试sleep 30 & script.pl `ps aux | egrep '[s]leep'`
egrep
是 grep -E
。 `ps ...`
的输出包含多个单词。这些作为命令行参数传递给我们的脚本,它使用第一个作为 PID。如果它有问题 运行 首先 ps
过滤然后手动输入 PID 作为脚本的输入参数。上面的30秒sleep
是为了给命令行足够的时间做这一切。
可以通过$name
匹配一个hard-coded$prog_name
来简化代码,如果程序名足够唯一并且不会改变的话。
hard-coded 名称 是上面使用的 ,但用于检查,如果不匹配它会生成警告。 (如果我们仅依赖于硬编码,那么如果它不匹配,我们将无法发出警告,因为那是代码操作的一部分。)
如果进程与脚本属于同一用户,则可以使用 kill 0, $pid
,如
while ( kill 0, $ext_pid ) { sleep 1 }
然后您要么必须再次调用以检查名称,要么满足于 $pid
代表的实际过程中出现错误的(小)可能性。
模块 Proc::ProcessTable
可用于其中的大部分内容