Perl:将打开的文件句柄传递给读取STDIN的程序

Ole*_*nge 6 perl redirect fork filehandle

我从STDIN读了几行.如何将剩余的STDIN传递给从标准输入读取的命令(例如md5sumwc)?

我可以做一个:

read_a_few_lines_from_diamond_operator();
open (C, "|cmd");
while(<>) { print C }
close C;
cleanup_after_C();
Run Code Online (Sandbox Code Playgroud)

但出于效率原因,我不想触摸输入,而是传递STDIN的文件句柄.有点像:

seq 10 | (read A; wc)
Run Code Online (Sandbox Code Playgroud)

read将其余部分传递给之前,尽可能多地读取wc.我不能使用这个解决方案,因为我需要从我的perl程序中启动命令,我需要在cmd完成后完成工作.


我从'foo'文件中读了几行.如何将剩余部分传递给从标准输入读取的命令(例如md5sumwc)?

我可以做一个:

open (F, "<foo");
read_a_few_lines_from_F();
open (C, "|cmd");
while(<F>) { print C }
close C;
cleanup_after_C();
Run Code Online (Sandbox Code Playgroud)

但出于效率原因,我不想触摸输入,而是传递文件'foo'的其余部分.


我有一种感觉,它可以使用欺骗等做select,open(FOO,">&STDOUT),exec 6<&0,fork,pipe.

ike*_*ami 8

答案很简单:你不需要做任何特别的事情.你的孩子将自动继承你STDINsystemexec.您从STDIN读取的所有内容都将由孩子阅读.

但是有一个问题.因为一次读取一个字符会非常低效,Perl会一次从文件中读取一个块.也就是说,您从文件中读取的内容比从Perl返回的"少行"中读取的内容更多.使用以下命令可以清楚地看到这一点:

perl -E'say $_ x 500 for "a".."z"' \
   | perl -e'<>; <>; exec("cat");' \
   | less
Run Code Online (Sandbox Code Playgroud)

而不是从第二行的cat开头开始,从"q"的中间开始(在字节8192处)!

如果你想让它工作,你必须从带有readline(<>)的读取行切换到读取单个字节sysread.


关注更大的图景,我认为有一个解决方案:

open(STDIN, "<", "foo") or die $!;
read_a_few_lines(*STDIN);
my $pos = tell(STDIN);
open(STDIN, "<", "foo") or die $!;
sysseek(STDIN, $pos, SEEK_SET);
system(@cmd);
...
Run Code Online (Sandbox Code Playgroud)

或者甚至可能:

open(STDIN, "<", "foo") or die $!;
read_a_few_lines(*STDIN);
sysseek(STDIN, tell(STDIN), SEEK_SET);
system(@cmd);
...
Run Code Online (Sandbox Code Playgroud)

未经测试.