2009-12-11 61 views
0

當我發出一個Perl腳本時,一些標準輸入,例如如何重置在Perl中接收標準輸入的文件句柄?

$ awk '{print $1"\t"$2}' foo.txt | myScript.pl 

我有一個包含bug的腳本。它讀取標準輸入的第一線,從第一行得到的東西,然後只能通過後續讀取標準輸入的n個解析線2:

open (FH, "< $input") or die $?; 
my $firstLine = <FH>; // reads first line 

... 

while (my $line = <FH>) { 
    // reads lines 2 through n 
} 
close (FH); 

所以我增加了一個seek聲明,此腳本來嘗試文件句柄復位到文件的開頭:

use Fcntl qw(:seek); 

... 

open (FH, "< $input") or die $?; 
my $firstLine = <FH>; // reads first line 
seek (FH, 0, SEEK_SET) or die "error: could not reset file handle\n"; // should reset file handle 

... 

while (my $line = <FH>) { 
    // reads lines 1 through n (in theory) 
} 
close (FH); 

添加此seek語句也適用於文件的輸入,而不是標準輸入。該腳本錯誤崩潰:

error: could not reset file handle 

我怎樣才能正確讀取標準輸入的第一行的腳本開始,重置文件句柄,然後讀取所有行1通過標準輸入的n個?

我想我可以寫一個特殊的案例來存儲和處理while循環之前的第一行,但我希望有一個更清晰的解決方案,這個問題允許我處理標準輸入和文件輸入。

回答

7

有一個簡單的方法:

open (FH, "< $input") or die $?; 
my $line = <FH>; // reads first line 

//do stuff with first line 

do { 
    //stuff 
} while ($line = <FH>); 
+0

當然!我完全忘了'做'時間。非常優雅,謝謝。 – 2009-12-11 06:25:31

+1

只記得下一個/最後一個沒有看到do {}作爲塊;有關標準解決方法,請參閱http://perldoc.perl.org/perlsyn.html#Statement-Modifiers。 – ysth 2009-12-11 17:21:22

2

編輯:我的第一種方法的缺點是它必須在處理列表之前將所有行從FH加載到內存中。這種做法,採用開放的標量的參考功能(自5.8.0可用)將不會存在這樣的問題:

my $firstline = <FH>; 
open(my $f1, '<', \$firstline); 

... 

while (my $line = <$f1> || <FH>) { 
    # process line 1 through n 
} 

如何:

for my $line ($firstline, <FH>) { 
    # process lines 1 through n 
} 
+0

我喜歡用'while'因爲我處理非常大的文件。正如您所說的,使用'for'需要在處理之前將所有輸入數據存儲在內存中。 – 2009-12-11 06:43:07

1

我不認爲你可以重置(或尋找(0))爲STDIN。它不像STDIN那樣是一個正常的文件句柄。由於它實際上不是文件,因此您需要STDIN執行可重置緩衝。

我認爲您需要專門處理第1行的讀取和重新使用。

+0

問題不在於它是STDIN,而是它不是一個文件。 seek將在其他文件句柄上失敗,這些文件句柄是管道或其他非可搜索類型;如果它是一個文件,seek即使在STDIN上也會成功,例如:'seq 9> foo; perl -we'seek STDIN,12,0;打印標量<>' ysth 2009-12-11 20:22:17

相關問題