为什么在给定命令错误时打开函数分叉?
Why open function forks when the given command is wrong?
在 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`);
我调用函数 safe 因为我遵循 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
我们可以看到,当我在 运行 执行错误命令后打印进程列表时,我有两个 perl 分支。当第一个结束时,第二个从 open
的调用继续。但是,当命令正确时,open
不会分叉。
我该怎么做才能避免这个分支(或管理它)并在命令错误时显示错误消息?
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
而不是 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");
}
我得到:
pierre 211968 11.5 0.0 26544 7244 pts/1 S+ 15:32 0:00 perl open.pl
pierre 211971 0.0 0.0 4320 768 pts/1 S+ 15:32 0:00 sh -c ps aux | egrep open
pierre 211973 0.0 0.0 12752 1064 pts/1 S+ 15:32 0:00 grep -E open
-----
good_command
End safe_run_cmd
pierre 211968 11.5 0.0 26544 7264 pts/1 S+ 15:32 0:00 perl open.pl
pierre 211975 0.0 0.0 4320 792 pts/1 S+ 15:32 0:00 sh -c ps aux | egrep open
pierre 211977 0.0 0.0 12752 1032 pts/1 S+ 15:32 0:00 grep -E open
在 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`);
我调用函数 safe 因为我遵循 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
我们可以看到,当我在 运行 执行错误命令后打印进程列表时,我有两个 perl 分支。当第一个结束时,第二个从 open
的调用继续。但是,当命令正确时,open
不会分叉。
我该怎么做才能避免这个分支(或管理它)并在命令错误时显示错误消息?
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
而不是 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");
}
我得到:
pierre 211968 11.5 0.0 26544 7244 pts/1 S+ 15:32 0:00 perl open.pl
pierre 211971 0.0 0.0 4320 768 pts/1 S+ 15:32 0:00 sh -c ps aux | egrep open
pierre 211973 0.0 0.0 12752 1064 pts/1 S+ 15:32 0:00 grep -E open
-----
good_command
End safe_run_cmd
pierre 211968 11.5 0.0 26544 7264 pts/1 S+ 15:32 0:00 perl open.pl
pierre 211975 0.0 0.0 4320 792 pts/1 S+ 15:32 0:00 sh -c ps aux | egrep open
pierre 211977 0.0 0.0 12752 1032 pts/1 S+ 15:32 0:00 grep -E open