如何使用perl进行打印而不重复?

时间:2013-03-04 06:34:38

标签: perl printing no-duplicates

我的作业比标题更深入,但标题是我的主要问题。这是作业:

编写一个perl脚本,该脚本将grep文件/目录列表中所有常规文件中出现的所有正则表达式,以及文件/目录列表中目录下的所有常规文件。 如果文件不是TEXT文件,则应首先通过unix命令字符串(无开关)操作该文件,并搜索结果行。如果-l开关只给出了应该打印包含正则表达式的文件的文件名,每行一个。在这种情况下,文件名最多应出现一次。如果没有给出-l开关,那么应该打印所有匹配的行,每行都按文件名和冒号在同一行上进行。从命令行调用示例:

plgrep'ba + d'file1 dir1 dir2 file2 file3 dir3

这是我的代码:

#!/usr/bin/perl -w

use Getopt::Long;
my $fname = 0;
GetOptions ('l' => \$fname);

$pat = shift @ARGV;
while (<>) {
    if (/$pat/) {
        $fname ? print "$ARGV\n" : print "$ARGV:$_";
    }
}

到目前为止,除了读取非文本文件并在使用-l开关时打印出重复的文件名之外,代码执行了它应该执行的所有操作。以下是在命令行中输入以下内容后输出的示例:plgrep'ba + d'file1 file2

  • file1:我的狗很糟糕。
  • file1:我的狗非常baaaaaad。
  • file2:我对吉他不好。
  • file2:尽管我对吉他不好,但玩起来仍然很有趣!

哪个完美! 但是当我使用-l开关只打印出文件名时,这就是我在命令行输入以下命令后得到的:plgrep -l'ba + d'file1 file2

  • 文件1
  • 文件1
  • file2的
  • file2的

如何摆脱这些重复项,只打印出来:

  • 文件1
  • file2的

我试过了:

$pat = shift @ARGV;
while (<>) {
    if (/$pat/) {
        $seen{$ARGV}++;
        $fname ? print "$ARGV\n" unless ($seen{$ARGV} > 1); : print "$ARGV:$_";
    }
}

但是当我尝试在没有-l开关的情况下运行它时我只得到:

  • file1:我的狗很糟糕。
  • file2:我对吉他不好。

我也尝试过:

$ fname?打印“$ ARGV \ n”除非($ ARGV&gt; 1):打印“$ ARGV:$ _”;

但是我一直在plgrep第17行,“$ ARGV \ n”附近得到语法错误,除非“

如果有人可以帮我解决我的重复问题以及作业的斜体部分,我会非常感激。我甚至不知道从哪个斜体开始。

2 个答案:

答案 0 :(得分:1)

如果您只打印文件名,则可以在第一次匹配后退出循环(使用last命令),因为您已经知道文件匹配。通过不扫描文件的其余部分,这也将阻止名称重复打印。

编辑添加:为了这样做,您还需要切换使用<>来读取文件,而不是从{{1}获取名称和@ARGV他们正常。

如果您想继续使用open,则需要观看<>以查看它何时发生变化(表明您已开始阅读新文件)并保留一个标记以指示当前文件是否已找到任何匹配项。但是,这种方法需要您完整地读取每个文件,这比仅读取每个文件足以知道它是否包含至少一个匹配(即,在第一个匹配后跳到下一个文件)效率低),所以我建议切换到$ARGV

答案 1 :(得分:0)

第一个语法问题只是一个额外的分号。

第二个是你只能在句子结尾处使用if / unless作为语句修饰符 - 你不能将它嵌入条件的中间。

$fname ? print "$ARGV\n" unless ($seen{$ARGV} > 1); : print "$ARGV:$_";

变为:

next if $seen{$ARGV} > 1;
print $fname ? "$ARGV\n" : "$ARGV:$_";