2

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

编写一个 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

  • 文件1:我的狗很坏。
  • 文件 1:我的狗非常棒。
  • file2:我吉他不好。
  • file2:虽然吉他弹得不好,但弹起来还是很有趣的!

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

  • 文件 1
  • 文件 1
  • 文件2
  • 文件2

我如何摆脱那些重复的,所以它只打印:

  • 文件 1
  • 文件2

我试过了:

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

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

  • 文件1:我的狗很坏。
  • file2:我吉他不好。

我也试过:

$f名称?打印 "$ARGV\n" 除非 ($ARGV > 1) : 打印 "$ARGV:$_";

但我一直在 plgrep 第 17 行出现语法错误,靠近 ""$ARGV\n" unless"

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

4

2 回答 2

1

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

编辑添加:为了做到这一点,您还需要从使用<>读取文件切换到正常获取名称@ARGV并从中获取名称open

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

于 2013-03-04T07:02:44.200 回答
0

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

第二个是您只能在语句末尾使用 if/unless 作为语句修饰符 - 您不能以这种方式将它嵌入到条件的中间。

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

变成:

next if $seen{$ARGV} > 1;
print $fname ? "$ARGV\n" : "$ARGV:$_";
于 2013-03-05T16:22:28.060 回答