Perl中STDOUT重定向到PTY时,\r\n来自何处?
为何Linux下Perl的PTY输出会出现CRLF?
我在Linux环境下运行以下Perl测试代码:
use strict; use warnings; use utf8; use IO::Pty; use Data::Dump qw(pp); my $pty = IO::Pty->new; open *STDOUT, '>&', $pty->slave; if ( my $pid = open *STDOUT, '|-' ) { # parent my $str = "foo\n"; print {*STDERR} "parent [1]: ", pp($str), "\n"; print {*STDOUT} $str; my $line = <$pty>; print {*STDERR} "parent [2]: ", pp($line), "\n"; } else { # child while (<>) { print {*STDERR} "child [1]: ", pp($_), "\n"; s/foo/bar/; print {*STDERR} "child [2]: ", pp($_), "\n"; print $_; } ## end while (<>) exit; } ## end else [ if ( my $pid = open *STDOUT...)]
运行后得到如下输出:
parent [1]: "foo\n" child [1]: "foo\n" child [2]: "bar\n" parent [2]: "bar\r\n"
我原本预期最后一行输出为"bar\n",但实际得到了"bar\r\n"。Linux环境下默认不会自动将LF转为CRLF,请问这个\r\n是从哪里来的?
这是因为PTY设备默认会启用换行转换模式(ONLCR)——当PTY从应用程序接收到LF(\n)时,会自动将其转换为CRLF(\r\n)再输出。
具体到你的代码逻辑:
- 子进程输出的
bar\n写入PTY slave端时,PTY驱动会自动把\n替换成\r\n - 父进程从PTY master端读取时,拿到的就是经过转换后的
bar\r\n
如果要禁用这个转换,可以在创建PTY后,修改其终端属性,关闭ONLCR选项:
use strict; use warnings; use utf8; use IO::Pty; use Data::Dump qw(pp); use POSIX qw(tcgetattr tcsetattr TCSANOW OPOST ONLCR); my $pty = IO::Pty->new; my $slave = $pty->slave; # 获取并修改PTY slave的终端属性,关闭ONLCR转换 my $termios = tcgetattr($slave) or die "tcgetattr failed: $!"; $termios->{c_oflag} &= ~(ONLCR); tcsetattr($slave, TCSANOW, $termios) or die "tcsetattr failed: $!"; open *STDOUT, '>&', $slave; if ( my $pid = open *STDOUT, '|-' ) { # parent my $str = "foo\n"; print {*STDERR} "parent [1]: ", pp($str), "\n"; print {*STDOUT} $str; my $line = <$pty>; print {*STDERR} "parent [2]: ", pp($line), "\n"; } else { # child while (<>) { print {*STDERR} "child [1]: ", pp($_), "\n"; s/foo/bar/; print {*STDERR} "child [2]: ", pp($_), "\n"; print $_; } ## end while (<>) exit; } ## end else [ if ( my $pid = open *STDOUT...)]
修改后,父进程读取到的输出就会是"bar\n",符合预期。
内容的提问来源于stack exchange,提问作者André Kugland
相关产品推荐
相关产品推荐

