【问题标题】:exit code of system() call with a single scalar argument in Perl在 Perl 中使用单个标量参数调用 system() 的退出代码
【发布时间】:2012-01-03 20:26:18
【问题描述】:

在带有多个管道的 Perl 脚本中有一个 system() 调用,使用单个标量参数。调用看起来或多或少是这样的:

system("zcat /foo.gz | grep '^.{6}X|Y|Z' | awk '{print $2,$3,$4,$6}' | bzip2 > /foo.processed.bz2");

有问题的文件 (foo.gz) 相当大,压缩后大小约为 2GB。我想这就是为什么它最初是通过系统调用完成的。

问题:

现在的问题是,无论系统命令之一是否失败,这个系统调用似乎总是返回 0。我认为这是因为它是通过sh -c '...' 调用的。对吗?

如果只传递一个标量参数,有没有办法检查system() 调用是否成功?

有没有更好的方法来处理这样的大文件,以同样或更高效率的方式(主要是在速度方面)?

感谢任何提示,因为我对 Perl 不是很熟悉。

【问题讨论】:

  • 如果您通过 perl 中的系统调用使用 grep...您不是在 perl 中编程 :)
  • 我知道,这是别人写的一些旧 Perl 代码,我也没有真正的经验,多好的组合 :) 无论如何,也许你给我一些想法如何做得更好以更优雅的方式?
  • 还有 $2, $3 部分引用 perl 代码中的变量,而不是 awk 代码。因为双引号。

标签: perl


【解决方案1】:

两件事:

  1. 当您执行系统调用时,返回的值是管道中的最后一个值。因此,您将获得bzip2 命令的状态代码。
  2. 程序这样做的原因是编写程序的人可能不知道更好。我见过 Perl 程序使用系统调用来查找文件的基本名称,进行查找,甚至进行复制/重命名/移动。这些都是在 Perl 程序中可以更快、更轻松地完成的事情。而且,您不会遇到所有 Windows/Unix 兼容性问题。

对于这样的事情,你总是最好使用 Perl 模块。在这种情况下,我敢打赌 Perl 模块将比 shell 管道更快,并且您将对整个操作有更多的控制权。

有一个名为 IO::Compress 的集合可以同时处理 Zip 和 BZip2。

我使用Archive::Zip,这是一个很棒的模块,但你想使用Bzip2 压缩算法,而Archive::Zip 无法处理。

【讨论】:

  • 感谢模块的建议,我去看看。
  • 你是说can't handle that吗?
  • @TLP - 是的,你是对的 Archive::Zip 无法处理 [bzip2 压缩]
【解决方案2】:

system() 返回 /bin/sh shell 返回的内容。当多个命令流水线化时,shell 会为每个命令派生一个新进程,并返回链中最后一个命令的状态码,在本例中为 bzip2

【讨论】:

    【解决方案3】:

    根据您的 cmets 和答案,我现在会这样做:

    $infile =~ s/(.*\.gz)\s*$/gzip -dc < $1|/;
    open(OUTFH, "| /bin/bzip > $outfile") or die "Can't open $outfile: $!";
    open(INFH, $infile) or die "Can't open $infile: $!";
    while (my $line = <INFH>) {
        if ($line =~ /^.{6}X|Y|Z) {
            # TODO: the awk part...
            print OUTFH $line;
        }
    }
    close(INFH);
    close(OUTFH);
    

    请随时发表评论并投票赞成/反对。

    【讨论】:

    • Awk 行可以在线拆分,例如:“my @fields = split(/\s+/, $line);”。这应该是 awk 的做法,它与 IFS 变量分开,我猜这已经足够接近了:)。此外,使用变量而不是 BIG LETTER 会更好,我忘记了它们是如何被调用的,例如:'open my $out_fh, "| /bin/bzip > $outfile" or die $!;'。看perl101
    • open my $infh, '-|', '/bin/zcat', $infile or die $! 可能是个好主意。
    【解决方案4】:

    你最好在 perl 内部进行文本处理——这就是 perl 的用途:)

    system() 只返回 0 或 1。要捕获实际输出,请尝试通过反引号调用它:`command` 而不是 system('command')

    【讨论】:

    • 这实际上是不准确的。 “返回值是等待调用返回的程序的退出状态。要获得实际的退出值,请右移八位。[...]返回值-1表示程序启动失败或错误wait(2) 系统调用 [...]。”
    猜你喜欢
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    相关资源
    最近更新 更多