Foreach循环与来自@ARGV的while(<>)“shift”组合

时间:2014-05-07 14:48:40

标签: perl

我有一个简单的任务,即创建一个以文件名作为参数的脚本,读取每个文件中的每一行并检查一些内容。

我试过这样做:

foreach $file (@ARGV){
    while (chomp($line = <>)){
         ...
    }
}

虽然我明白虽然只是阅读所有文件,并且这种方法不好,但我注意到在每次“foreach”迭代后,@ ARGV丢失了一个条目,好像有一个

shift @ARGV;

如果没有

,则不会发生

这是我不理解的部分,想要解释。为什么@ARGV每次只减少1个元素?

例如,如果我用

调用脚本
./test.pl localhost_access_log*.txt

并且有文件

localhost_access_log.2008-02-24.txt
localhost_access_log.2008-02-25.txt

在当前文件夹中,在foreach循环之后,@ ARGV将不会同时拥有它们,而只有一个。

2 个答案:

答案 0 :(得分:6)

perldoc

中记录了此行为
while (<>) {
    ...         # code for each line
}

等效于以下类似Perl的伪代码:

unshift(@ARGV, '-') unless @ARGV;
while ($ARGV = shift) {
  open(ARGV, $ARGV);
  while (<ARGV>) {
      ...       # code for each line
  }
}
  

它确实会移动@ARGV数组并将当前文件名放入$ARGV变量中。它还在内部使用文件句柄ARGV<>只是<ARGV>的同义词,这是神奇的。 (上面的伪代码不起作用,因为它将<ARGV>视为非魔法。)

答案 1 :(得分:4)

ARGV读取已遍历@ARGV,因此您的代码毫无意义。也许您不知道<>表示readline(ARGV)while (<>)表示while (defined($_ = readline(ARGV)))while ($line = <>)表示while (defined($line = readline(ARGV)))。你应该使用

while ($line = <>) {
    chomp($line);
    ...
}

ARGV会在@ARGV打开它们时删除。例如,

print "Files to read: @ARGV\n";
while (<>) {
    chomp;
    print "Read $_ from $ARGV. Files left to read: @ARGV\n";
}

给出

$ script foo bar baz
Files to read: foo bar baz
Read foo1 from foo. Files left to read: bar baz
Read foo2 from foo. Files left to read: bar baz
Read bar1 from bar. Files left to read: baz
Read bar2 from bar. Files left to read: baz
Read baz1 from baz. Files left to read:
Read baz2 from baz. Files left to read: