6

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

我可以做一个:

read_a_few_lines_from_diamond_operator();
open (C, "|cmd");
while(<>) { print C }
close C;
cleanup_after_C();

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

seq 10 | (read A; wc)

read将其余部分传递给wc. 但是,我不能使用这个解决方案,因为我需要从我的 perl 程序中启动命令,并且我需要在cmd完成后进行工作。


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

我可以做一个:

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

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


我有一种感觉,可以使用诸如select, open(FOO,">&STDOUT), exec 6<&0, fork,之类的诡计来完成pipe

4

1 回答 1

8

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

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

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

不是从第二行的开头开始,而是从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);
...

甚至可能:

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

未经测试。

于 2012-08-30T23:27:30.153 回答