2012-08-30 57 views
6

我从STDIN读了几行。如何将剩余的STDIN传递给从标准输入读取的命令(例如md5sumwc)?Perl:将打开的文件句柄传递给程序读取STDIN

我可以做一个:

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

但efficency原因,我想不要触摸输入,而是通过STDIN的文件句柄。有点像:

seq 10 | (read A; wc) 

其中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(); 

但efficency原因,我想不要触摸输入,而是通过文件“富”的其余部分。


我有一种感觉,它可以用诡计像selectopen(FOO,">&STDOUT)exec 6<&0forkpipe来完成。

回答

8

答案很简单:你不需要做任何特别的事情。您的孩子将自动继承STDINsystemexec。你没有从STDIN读取的所有东西都可以被孩子读取。

虽然有一个问题。因为一次读取一个字符会非常麻烦,Perl每次从文件中读取一个字符块。也就是说,您从文件中读取的内容比从Perl获取的“少数几行”更多。这可以清楚地使用下面的命令可以看出:

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

,而不是启动第二行的开始,cat开始在“Q” S的中部(以字节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); 
... 

未经检验。

+0

优雅的解决方案,让你竖起大拇指,但它有两个问题:它杀死perl(我澄清了这个问题,以清楚表明这不会对我有用);它不涉及第二部分(读取'foo'文件)。 –

+0

它为什么不起作用?就像答案所说,它适用于'system'和'exec'。 'perl -e'print <>;系统( “猫”);打印“仍然在这里\ n”' tripleee

+0

斑点。这工作:'seq 10 | perl -e'sysread(STDIN,$ a,1);打印“$ a bar”;系统(“猫”);打印“仍然在这里\ n”''。尽管如此,它仍然会读取文件'foo'。 –