2012-08-30 88 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'。 –