如何重置在 Perl 中接收标准输入的文件句柄?

发布于 2024-08-14 03:39:49 字数 1036 浏览 10 评论 0原文

当我发出 Perl 脚本时一些标准输入,例如

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

我有一个包含错误的脚本。它读取标准输入的第一行,从第一行获取一些内容,然后在后续读取时仅解析标准输入的第 2 行到第 n 行:

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 循环之前的第一行,但我希望有一个更清晰的解决方案来解决这个问题,使我能够处理标准输入和文件输入。

When I issue a Perl script some standard input, e.g.

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

I have a script which contains a bug. It reads the first line of standard input, gets something from that first line, and then only parses lines 2 through n of standard input on subsequent read:

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

...

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

So I added a seek statement to this script to try to reset the file handle to the beginning of the file:

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);

Adding this seek statement works for file input, but not for standard input. The script crashes with the error:

 error: could not reset file handle 

How can I correctly read the first line of standard input at the start of the script, reset the file handle and then read all lines 1 through n of the standard input?

I guess I can write a special case for storing and processing the first line before the while loop, but I'm hoping there is a cleaner solution to this problem that allows me to handle both standard input and file input.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

笙痞 2024-08-21 03:39:49

有一个简单的方法:

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

//do stuff with first line

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

There's an easy way:

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

//do stuff with first line

do {
    //stuff
} while ($line = <FH>);
疑心病 2024-08-21 03:39:49

编辑:我的第一种方法的缺点是它必须在处理列表之前将所有行从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
}

EDIT: Drawback of my first approach is that it must load all lines from FH into memory before processing the list. This approach, using the open to scalar reference feature (available since 5.8.0) won't have that problem:

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

...

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

How about:

for my $line ($firstline, <FH>) {
    # process lines 1 through n
}
贪恋 2024-08-21 03:39:49

我认为您无法重置(或搜索(0))STDIN。它不是标准输入那样的普通文件句柄。由于它实际上不是一个文件,因此您需要 STDIN 进行可重置缓冲。

我认为你需要专门处理第一行的读取和重用。

I don't think you can reset (or seek(0)) for STDIN. It isn't a normal file handle as STDIN. Since it isn't actually a file, you would require the STDIN does resettable buffering.

I think you'll need to handle the reading and re-using of line 1 specially.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文