2

我对 perl 编程比较陌生,我试图弄清楚 open3 是如何工作的。这是代码。

#!/usr/bin/perl 
use strict;
use warnings;
use IPC::Open3;

my $dir = "/home/vman/Documents/Dev/perl_scripts/Provenance/temp";

my $fileHandle;
my $bashPid;

print "Starting main program\n";

my $pid = fork();

if($pid)#Parent process2
{
    print("Start transfer.\n");
    $bashPid = $pid;

    #Attaching an strace to the executed command which happens in the child process
    open3(\*WRITE, \*READ,\*ERROR,"strace", "-f", "-F", "-e", "trace=open,execve","-p", $bashPid, "-s", "2097152","-q");

    while(<READ>)
    {
        print("Here1\n");
        print("$_");
    }

    while(<ERROR>)
    {
        print("$_");
    }

    print("Finish transfer.\n");
}
elsif($pid == 0)
{
    if (scalar(@ARGV == 0))
    {
        exit
    }

    my $args = join(' ', @ARGV);
    exec($args);
}
else
{
    die("Could not fork.");
}

close(READ);
close(WRITE);
close(ERROR);

waitpid($bashPid, 0);

print "End of main program\n";

我想在 bash 进程上运行 strace,然后在输出时捕获所有输出。然后我将获取该输出并对其进行解析,以查看哪个进程正在更改哪些文件,并将这些更改保存在 mysql 数据库中。现在我要做的就是将一个 strace 附加到现有的 bash 进程上,并在正在运行的 bash 终端中打印该 strace 的输出,以确保它异步读取输出。

问题之一是我通过 ERROR 文件句柄获取输出。我对为什么会发生这种情况有点困惑。我是否对 open3 使用了正确的顺序,如果出现错误,为什么正确的输出甚至会输出到 stderr?

我遇到的第二个问题是我只有在 exec 结束时才得到输出,这不好,因为它需要在 exec 运行时完成。我认为 open3 是异步运行的。

根据建议,这就是我所做的,并且效果很好。

#!/usr/bin/perl 
use strict;
use warnings;
use IPC::Run3;

my $bashPid;

print "Starting main program\n";
my $pid = fork(); 

if($pid)#Parent process
{
    print("Start transfer.\n");
    $bashPid = $pid;

    #Attaching an strace to the executed command which happens in the child process
    my $command = "strace -fFe trace=open,execve -p $bashPid -s 2097152 -q";

    run3($command, \*STDIN, \*STDOUT, \*STDERR);

    if ($?)
    {
        die "something went horribly wrong";
    }

    while(<STDERR>)
    {
        print($_);
    }

    print("Finish transfer.\n");
}
elsif($pid == 0)#cild process
{
    if (scalar(@ARGV == 0))
    {
        exit
    }

    my $args = join(' ', @ARGV);
    exec($args);
}
else
{
    die("Could not fork.");
}

close(STDIN);
close(STDOUT);
close(STDERR);

waitpid($bashPid, 0);

print "End of main program\n";
4

1 回答 1

2

问题之一是我通过 ERROR 文件句柄获取输出

正确的。strace写入 STDERR。

我遇到的第二个问题是我只有在 exec 结束时才得到输出,这不好,因为它需要在 exec 运行时完成。我认为 open3 是异步运行的。

那是因为您只有在孩子结束时关闭其 STDOUT 后才开始从孩子的 STDERR 读取。

事实上,你很幸运,你还没有陷入僵局。通过像您当前一样一次读取一个,当strace输出足以填满管道时,您将陷入僵局。

您需要从孩子的 STDOUT 和 STDERR 中读取它。您可以在select轮询非阻塞句柄或线程的帮助下执行此操作。这些选项都不像放弃open3并使用为您处理此问题的更高级别的模块那么简单。更简单的IPC::Run3和功能齐全的IPC::Run是不错的选择。

于 2013-04-15T16:00:25.887 回答