我从STDIN读了几行。如何将剩余的STDIN传递给从标准输入读取的命令(例如md5sum
或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'文件中读了几行。如何将剩余部分传递给从标准输入读取的命令(例如md5sum
或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
这样的技巧来完成。
答案 0 :(得分:8)
答案很简单:你不需要做任何特别的事情。您的孩子将使用STDIN
和system
自动继承您的exec
。您从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);
...
未测试。