生成守护进程时,为什么会剥离utf8 IO层?

时间:2019-04-19 23:09:46

标签: perl encoding utf-8

以下代码按预期工作:

use feature qw(say);
use strict;
use warnings;
use open qw/:std IN :encoding(utf-8) OUT :utf8/; 

say  join ' ', (PerlIO::get_layers(\*STDOUT));
my $pid = fork();
die "fork() failed: $!" unless defined $pid;
if ($pid == 0) {
    say  join ' ', (PerlIO::get_layers(\*STDOUT));
}

输出

unix perlio utf8
unix perlio utf8

但是如果我使用守护进程而不是常规的fork:

use feature qw(say);
use strict;
use warnings;
use open qw/:std IN :encoding(utf-8) OUT :utf8/; 
use Cwd qw(getcwd);
use Proc::Daemon;

my $work_dir = getcwd;    
my $daemon = Proc::Daemon->new(
    work_dir     => $work_dir,
    child_STDOUT => 'stdout.txt',
    child_STDERR => 'stderr.txt',
    pid_file     => 'pid.txt',
);
my $pid = $daemon->Init();
if ( $pid == 0 ) {
    say  join ' ', (PerlIO::get_layers(\*STDOUT));
}

文件stdout.txt的输出为:

unix perlio

因此utf8 IO层已被剥离。

1 个答案:

答案 0 :(得分:2)

考虑以下示例:

Foo.pm:

package Foo;
use warnings;
use strict;
sub test {
  close STDIN;
  open \*STDIN, "<", "/dev/null";
}
1;

test.pl:

#!/usr/bin/perl
use strict;
use warnings;
use feature qw/say/;
use open qw/:std IN :encoding(UTF-8) OUT :encoding(UTF-8)/;
use lib qw/./;
use Foo;

$, = ' ';
say "Original STDIN:", PerlIO::get_layers(\*STDIN);
close STDIN;
open \*STDIN, "<", "/dev/null";
say "Reopened STDIN:", PerlIO::get_layers(\*STDIN);
Foo::test();
say "Reopened STDIN in different package:", PerlIO::get_layers(\*STDIN);

结果:

$ perl test.pl
Original STDIN: unix perlio encoding(utf-8-strict) utf8
Reopened STDIN: unix perlio encoding(utf-8-strict) utf8
Reopened STDIN in different package: unix perlio

看起来像use open就像其他编译指示一样,仅适用于其中的文件。因此,Proc::Daemon关闭标准输入,输出和错误,然后重新打开它们时,自然看不到多余的层。