在Perl中,如何通过菱形操作符对命令行上指定的所有文件进行两次传递?

在Perl中,如何通过菱形操作符对命令行上指定的所有文件进行两次传递?,perl,Perl,如果我有一个文本文件,我想运行两种类型的操作,但每个操作必须分别读取文本的每一行。我知道怎么做的唯一方法就是 open out,(">>out.txt"); while (<>){ #operation one } while (<>){ #operation two } close out; openout,(“>>out.txt”); 而(){ #第一次行动 } 而(){ #行动二 } 收尾; 但是,这将仅在第一个while上运行,其中

如果我有一个文本文件,我想运行两种类型的操作,但每个操作必须分别读取文本的每一行。我知道怎么做的唯一方法就是

open out,(">>out.txt");
while (<>){
    #operation one
}
while (<>){
    #operation two
}
close out;
openout,(“>>out.txt”);
而(){
#第一次行动
}
而(){
#行动二
}
收尾;

但是,这将仅在第一个
while
上运行,其中操作运行正常,但第二个将不会完成,因为第二个
while()
实际上不会重新读取文件,而是尝试从第一个while()离开的位置继续。在文件的末尾。那么还有别的办法吗?或者有没有办法告诉第二个while在开始时重新开始?

如果没有使用菱形运算符的文件句柄,Perl将检查
@ARGV
特殊变量。如果
@ARGV
没有元素,则菱形运算符将从
STDIN
读取

这是实现您的需求的另一种方式:

my @stdin=<>;

foreach my $item( @stdin ) {
   # ...
}

foreach my $item( @stdin ) {
   # ...
}
my@stdin=;
foreach my$项目(@stdin){
# ...
}
foreach my$项目(@stdin){
# ...
}

如果您是从实际文件中读取,您可以使用

seek FILEHANDLE,0,0;

但是,您使用的是
stdin
,我认为不可能倒带
stdin
并重新开始。

如果数据适合内存:

my @lines = <>;

for ( @lines ){
  # operation one
}

for ( @lines ){
  # operation two
}
my@lines=;
对于(@行){
#第一次行动
}
对于(@行){
#行动二
}

您在评论中提到:

 perl example.pl text.txt 
答案是-不要使用
,而是打开一个文件句柄

my ( $filename ) = @ARVG;

open ( my $input, "<", $filename ) or die $!;

while ( <$input> ) { 
    print; 
}

seek ( $input, 0, 0 ); 

while (  <$input> ) { 
    #something else
}
如果要在命令行上指定多个文件,可以将整个文件包装在
foreach
循环中:

foreach my $filename ( @ARVG ) { 
    ## open; while; seek; while etc. 
}

如果您需要逐行运行操作,为什么不试试这样的方法呢

sub operation_1 {
   my $line = shift;
   #processing for operation 1
}

sub operation_2 {
   my $line = shift;
   #processing for operation 2
} 

while(<>) {
   my $line = $_;
   chomp($line);
   operation_1($line);
   operation_2($line); 
}
子操作\u 1{
我的$line=shift;
#操作1的处理
}
子操作2{
我的$line=shift;
#操作2的处理
} 
while(){
我的$line=$\ux;
chomp($line);
行动1($线);
行动2($线);
}

您不能简单地使用以下命令吗

while (<>) {
   operation1($_);
   operation2($_);
}
当然,如果
读取的不是普通文件或指向普通文件的符号链接,它将失败。(使用
seek
的任何解决方案也是如此)唯一可行的方法是将整个文件加载到临时存储器中(例如内存或临时文件)。以下是最简单的例子:

my @lines = <>;
for (@lines) { operation1($_); }
for (@lines) { operation2($_); }
my@lines=;
对于(@lines){operation1($);}
对于(@lines){operation2($);}

您可以在第一次通过前本地化
@ARGV

#!/usr/bin/env perl

use strict;
use warnings;


{
    local @ARGV = @ARGV;
    while (<>){
        print "Pass 1: $_";
    }
}

while (<>){
    print "Pass 2: $_";
}
#/usr/bin/env perl
严格使用;
使用警告;
{
本地@ARGV=@ARGV;
而(){
打印“通过1:$\”;
}
}
而(){
打印“通行证2:$\”;
}

关闭/重新打开文件,或者将其打开。我无法做到这一点,在从命令行perl ex.pl text.txt调用后,我想用一条命令完成所有这一切,就像我说的,倒带文件。这将重置指向所需服务器的文件指针,以便从该点继续读取。e、 g.第一个while将指针保留在文件的末尾,因此您倒带开头,第二个while开始读取,就好像文件刚刚打开一样。@Kostas如果要传递文件名
text.txt
将其存储在变量中,请打开指向该文件名的文件句柄,然后从那里而不是从STDIN读取。然后你就可以按照Marc B的建议重新打开文件了;在这两段时间里,它没有改变任何东西,而且@Hunter我不知道如何做你说的我尝试过它,它没有改变任何东西,程序仍然在fist之后结束。@hymie是的,out是结果输出,因为我调用了我在命令行中作为参数读取的文件,使用seek的正确方法是什么?命令是这样的,perl example.pl text.txt难道没有办法吗?@ikegami:如果你想回答这个问题,那就自己回答这个问题。请不要更改我给出的答案中的每一个单词。这个答案充满了失败:(
的缩写,不是
,而且肯定不是
(因为
stdin
根本不存在)。至于“倒带”
ARGV
(或者
stdin
),这很容易测试,结果是当它是一个普通文件的句柄时,您就可以了。最初的问题没有提到使用任何参数。他所拥有的只是一个名为
的perl脚本。这将是
stdin
,除非专门传递了一个参数,这(再次)他没有说他在做什么。
stdin
是公认的“标准输入”的缩写,
stdin
是指向
stdin
的perl文件句柄。问题的答案是正确的。问题错了不是我的错。以下是OP自己的评论:“因此,当从stdin调用时,我应该将seek与filehandle的默认名称一起使用"。是否确实要
本地$/;
?这不会将整个文件拖到一个数组元素中吗?在列表上下文中访问文件句柄将使用
$/
记录定界符拖慢它。@Sobrique:Oops。您是对的。修复了它。谢谢。注意:如果
读取某个内容,则
查找
解决方案将失败而不是普通文件或普通文件的符号链接。
my @lines = <>;
for (@lines) { operation1($_); }
for (@lines) { operation2($_); }
#!/usr/bin/env perl

use strict;
use warnings;


{
    local @ARGV = @ARGV;
    while (<>){
        print "Pass 1: $_";
    }
}

while (<>){
    print "Pass 2: $_";
}