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 プロセスにアタッチし、その strace の出力を実行中の bash ターミナル内に出力して、非同期で出力を読み取っていることを確認することだけです。

問題の 1 つは、エラー ファイルハンドルを介して出力を取得していることです。なぜこれが起こっているのか、少し混乱しています。open3 に正しい順序を使用していますか? エラーがある場合、正しい出力が stderr に出力されるのはなぜですか?

私が抱えている2番目の問題は、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

問題の 1 つは、エラー ファイルハンドルを介して出力を取得していることです。

正しい。straceSTDERR に書き込みます。

私が抱えている2番目の問題は、execの実行中に実行する必要があるため、execが終了したときにのみ出力を取得していることです。open3 は非同期で実行されると思いました。

これは、子が終了時に STDOUT を閉じた後でのみ、子の STDERR から読み取りを開始するためです。

実際、まだデッドロックしていないのは幸運です。現在のように一度に 1 つずつ読み取るとstrace、パイプを満たすのに十分な出力があるときにデッドロックします。

子の STDOUT と STDERR の両方が入ってくると、それを読み取る必要があります。これはselect、ノンブロッキング ハンドルまたはスレッドのポーリングを使用して行うことができます。これらのオプションはどれも、open3これを処理する上位レベルのモジュールを捨てて使用するほど単純ではありません。より単純なIPC::Run3とフル機能のIPC::Runが良い選択です。

于 2013-04-15T16:00:25.887 に答える