【问题标题】:zcat working in command line but not in perl scriptzcat 在命令行中工作,但不在 perl 脚本中
【发布时间】:2016-09-26 11:02:16
【问题描述】:

这是我的脚本的一部分:

foreach $i ( @contact_list ) {

    print "$i\n";

    $e = "zcat $file_list2| grep $i";
    print "$e\n";

    $f = qx($e);
    print "$f";                                       
}

$e 可以正确打印,但即使$file_list2$i 匹配,$f 也会给出一个空行。

谁能告诉我为什么?

【问题讨论】:

  • 那个编辑摘要应该是“在你的答案中添加代码时请注意降价”。另外,欢迎使用 Stack Overflow。
  • 变量中有什么?你为什么不使用zgrep
  • 如果输入很大(正如压缩格式所暗示的那样),一次获得所有匹配项似乎是一种更好的方法。
  • 我编辑了这个问题,很抱歉第一次把它弄得这么凌乱,这就是这个门户的新手。我也尝试了 zgrep,即使它似乎不起作用。
  • 很可能,您的问题出在$i。呈现的代码容易受到有趣的数据解释问题的影响。例如,您可能在输入中包含空格或其他 shell 元字符,这会导致 grep 行为不端。但是,除非您在问题中添加一些输入样本,否则很难确定。

标签: perl zcat


【解决方案1】:

总是使用 Perl 的 grep 而不是使用管道更好:

@lines = `zcat $file_list2`;    # move output of zcat to array
die('zcat error') if ($?);      # will exit script with error if zcat is problem
# chomp(@lines)                 # this will remove "\n" from each line

foreach $i ( @contact_list ) {

    print "$i\n";

    @ar = grep (/$i/, @lines);
    print @ar;
#   print join("\n",@ar)."\n";      # in case of using chomp
}

最好的解决方案不是调用 zcat,而是使用 zlib 库: http://perldoc.perl.org/IO/Zlib.html

use IO::Zlib;

# ....
# place your defiiniton of $file_list2 and @contact list here.
# ...

$fh = new IO::Zlib; $fh->open($file_list2, "rb")
    or die("Cannot open $file_list2");
@lines = <$fh>;
$fh->close;

#chomp(@lines);                    #remove "\n" symbols from lines
foreach $i ( @contact_list ) {

    print "$i\n";
    @ar = grep (/$i/, @lines);
    print (@ar);
#   print join("\n",@ar)."\n";    #in case of using chomp
}

【讨论】:

    【解决方案2】:

    您的问题让我们猜测很多事情,但更好的整体方法似乎是只打开文件一次,并在 Perl 中处理每一行。

    open(F, "zcat $file_list |") or die "$0: could not zcat: $!\n";
    LINE:
    while (<F>) {
        ######## FIXME: this could be optimized a great deal still
        foreach my $i (@contact_list) {
            if (m/$i/) {
                print $_;
                next LINE;
            }
        }
    }
    close (F);
    

    如果您想从内部循环中挤出更多内容,请在循环之前将 @contact_list 中的正则表达式编译成一个单独的数组,或者如果您只关心其中一个是否匹配,则可以将它们组合成一个正则表达式。另一方面,如果您只想在知道它们是什么的情况下仅在最后打印一个模式的所有匹配项,则将每个搜索表达式的匹配项收集到一个数组中,然后循环它们并在您对整个输入集进行 grep 后打印文件。

    如果没有关于 $i 中内容的信息,您的问题是无法重现的,但我可以猜测它包含一些 shell 元字符,导致它在 grep 运行之前由 shell 处理。

    【讨论】:

    • @contact_list 是一个包含 355k 邮件 ID 的数组,我需要检查这些邮件 ID 是否存在于我的 zip 文件中的数据库中。所以我需要检查这些 355k 邮件 ID 中的每一个是否存在于 zip 文件中。 zip文件本身也有400万条记录,因此我试图避免打开它并使用zcat或zgrep
    • 是的,因此循环搜索 355k 次可能比循环整个输入文件 355k 次要快得多。
    • 这不能回答问题,而且几乎可以肯定不能解决问题。