如何获取在 Perl 脚本中执行的程序的 PID

How to get the PID of a program executed within a Perl script

This answer 解释了在使用 Perl 的 exec() 时如何获取新进程的 pid。 pid 甚至没有改变,所以您需要做的就是获取原始脚本的 pid。但如果我将输出重定向到一个文件作为命令的一部分,它就不起作用,这是我需要做的。

say "my pid is $$";
exec("childscript.pl");                  # same pid

但是如果我将输出重定向为命令的一部分:

say "my pid is $$";
exec("childscript.pl > log.txt");        # different pid, usually old pid + 1
exec("childscript.pl > log.txt 2>&1 &"); # same

那么新的pid比旧的pid大一(这可能只是因为它们是连续产生的,不可靠)。我通过查看输出和将 sleep 30 插入 "childscript.pl" 来测试它,这样我就可以用 ps -e.

看到它

我的猜测是重定向输出会导致新进程进行写入。但是我需要程序的 pid,除了我可以执行它之外,我无法控制程序。 (它也需要在后台 运行。)

当你用一个参数调用 exec 时(那个参数包含 shell 个元字符),perl 会自动为你运行 sh -c ARG。在你的情况下:

exec("childscript.pl > log.txt");
# really means:
exec("/bin/sh", "-c", "childscript.pl > log.txt");

即您的脚本将 sh 加载到当前 运行 进程中,并保留其 PID。 shell 执行输出重定向,然后运行 ​​childscript.pl 作为子进程(使用新的 PID)。

有两种方法可以解决这个问题:

  1. 在 Perl 中进行输出重定向并且不生成 shell:

    open STDOUT, ">", "log.txt" or die "[=11=]: log.txt: $!\n";
    exec "childscript.pl";
    die "[=11=]: childscript.pl: $!\n";
    
  2. 告诉 shell 也使用 exec 而不是生成子进程:

    exec "exec childscript.pl > log.txt";
    die "[=12=]: childscript.pl: $!\n";