为什么给定命令错误时打开函数会分叉?

问题描述 投票:1回答:1

在Perl脚本中,我想执行系统命令并在控制台中写入输出。这是一个重现我脚本行为的代码段:

use strict;
use warnings FATAL => 'all';

sub safe_run_cmd {
    my ($cmd) = @_;
    my $pid;
    my $sleep_count;
    my $fcmd;

    do {
        $pid = open($fcmd, "$cmd 2>&1 |");
        unless(defined $pid) {
            warn("Cannot fork: $!\n");
            die("Bailing out\n") if $sleep_count++ > 6;
            sleep(1);
        }
    } until (defined $pid);

    if($pid) {
        while ( my $line = <$fcmd> ) {
            print $line;
        }
        close $fcmd;
    } else {
        exit(0);
    }

    print("End safe_run_cmd\n");
}   

eval{safe_run_cmd("bad_command")};
print(`ps aux | egrep open`);

print("-----\n");

eval{safe_run_cmd("echo good_command")};
print(`ps aux | egrep open`);

我称为函数安全是因为我遵循documentation中的描述。

如果运行脚本,我会得到这个:

pierre 146161 21.0  0.0  21916  4548 pts/1    S+   14:32   0:00 perl open.pl
pierre 146163  0.0  0.0  21916  2816 pts/1    S+   14:32   0:00 perl open.pl
pierre 146164  0.0  0.0   4320   756 pts/1    S+   14:32   0:00 sh -c ps aux | egrep open
pierre 146166  0.0  0.0  12752  1008 pts/1    S+   14:32   0:00 grep -E open
-----
good_command
End safe_run_cmd
pierre 146161 10.5  0.0  21916  4548 pts/1    S+   14:32   0:00 perl open.pl
pierre 146163  0.0  0.0  21916  3516 pts/1    S+   14:32   0:00 perl open.pl
pierre 146168  0.0  0.0   4320   756 pts/1    S+   14:32   0:00 sh -c ps aux | egrep open
pierre 146170  0.0  0.0  12752   996 pts/1    S+   14:32   0:00 grep -E open
End safe_run_cmd
pierre 146161 10.5  0.0  21916  4744 pts/1    S+   14:32   0:00 perl open.pl
pierre 146171  0.0  0.0   4320   708 pts/1    S+   14:32   0:00 sh -c ps aux | egrep open
pierre 146173  0.0  0.0  12752  1008 pts/1    S+   14:32   0:00 grep -E open
-----
good_command
End safe_run_cmd
pierre 146161 10.5  0.0  21916  4744 pts/1    S+   14:32   0:00 perl open.pl
pierre 146175  0.0  0.0   4320   788 pts/1    S+   14:32   0:00 sh -c ps aux | egrep open
pierre 146177  0.0  0.0  12752  1012 pts/1    S+   14:32   0:00 grep -E open

我们可以看到,当我运行bad命令后打印进程列表时,我有两个perl分支。当第一个结束时,第二个继续从open的调用开始。但是,当命令正确时,open不分叉。

如何避免此派生(或管理它)并在命令错误时显示错误消息?

perl fork ipc
1个回答
2
投票

warnings FATAL => 'all'的使用对open功能有副作用。的确,如果open得到警告,它将立即死亡。因此,如果我从代码中删除它,则会得到正确的输出:

Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
Cannot fork: No such file or directory
pierre 207725  2.3  0.0  21644  4432 pts/1    S+   15:28   0:00 perl open.pl
pierre 207750  0.0  0.0   4320   816 pts/1    S+   15:28   0:00 sh -c ps aux | egrep open
pierre 207752  0.0  0.0  12752   984 pts/1    S+   15:28   0:00 grep -E open
-----
good_command
End safe_run_cmd
pierre 207725  2.3  0.0  21644  4448 pts/1    S+   15:28   0:00 perl open.pl
pierre 207754  0.0  0.0   4320   748 pts/1    S+   15:28   0:00 sh -c ps aux | egrep open
pierre 207756  0.0  0.0  12752   996 pts/1    S+   15:28   0:00 grep -E open

要在命令不存在时自动死亡,可以使用autodie代替autodie块:

do

我得到:

sub safe_run_cmd {
    my ($cmd) = @_;
    my $pid;
    my $sleep_count;
    my $fcmd;

    use autodie;
    $pid = open($fcmd, "$cmd 2>&1 |");

    while ( my $line = <$fcmd> ) {
        print $line;
    }
    close $fcmd;

    print("End safe_run_cmd\n");
}
© www.soinside.com 2019 - 2024. All rights reserved.