2

我正在使用 (GNU) 处理一个巨大的文件awk,(其他可用的工具是:Linux shell 工具,一些旧的(> 5.0)版本的 Perl,但无法安装模块)。

我的问题:如果某个field1,field2,field3包含X,Y,ZI必须在另一个目录中搜索包含field4和field5的文件,并将找到的文件中的一些数据插入到当前输出中。

例如:

实际文件行:

f1 f2 f3 f4 f5
X  Y  Z  A  B

现在我需要搜索另一个文件(在另一个目录中),其中包含例如

f1 f2 f3 f4
A  U  B  W

$0从原始文件和找到的文件写入 STDOUT ,然后处理原始文件的下一行。f2f3

有可能做到awk吗?

4

4 回答 4

2

让我首先说您的问题描述并没有那么有帮助。下一次,请更具体一点:您可能会错过更好的解决方案。

因此,根据您的描述,我了解到您有两个包含空格分隔数据的文件。在第一个文件中,您希望将前三列与某个搜索模式进行匹配。如果找到,您想查找另一个文件中包含第一个文件中匹配行的第四列和第五列的所有行。从这些行中,您需要提取第二列和第三列,然后打印第一个文件的第一列以及第二个文件的第二列和第三列。好的,这里开始:

#!/usr/bin/env perl -nwa
use strict;
use File::Find 'find';
my @search = qw(X Y Z);

# if you know in advance that the otherfile isn't
# huge, you can cache it in memory as an optimization.

# with any more columns, you want a loop here:
if ($F[0] eq $search[0]
    and $F[1] eq $search[1]
    and $F[2] eq $search[2])
{
  my @files;
  find(sub {
      return if not -f $_;
      # verbatim search for the columns in the file name.
      # I'm still not sure what your file-search criteria are, though.
      push @files, $File::Find::name if /\Q$F[3]\E/ and /\Q$F[4]\E/;
      # alternatively search for the combination:
      #push @files, $File::Find::name if /\Q$F[3]\E.*\Q$F[4]\E/;
      # or search *all* files in the search path?
      #push @files, $File::Find::name;
    }, '/search/path'
  )
  foreach my $file (@files) {
    open my $fh, '<', $file or die "Can't open file '$file': $!";
    while (defined($_ = <$fh>)) {
      chomp;
      # order of fields doesn't matter per your requirement.
      my @cols = split ' ', $_;
      my %seen = map {($_=>1)} @cols;
      if ($seen{$F[3]} and $seen{$F[4]}) {
        print join(' ', $F[0], @cols[1,2]), "\n";
      }
    }
    close $fh;
  }
} # end if matching line

与另一个包含大量系统调用的发布者的解决方案不同,这根本不会退回到 shell,因此应该足够快。

于 2008-09-29T07:19:02.943 回答
1

这是让我首先从 awk 转到 perl 的工作类型。如果您要完成此操作,您实际上可能会发现创建一个创建 awk 脚本以进行查询然后在单独的步骤中更新的 shell 脚本更容易。

(我写了这样一个用于读取/更新 windows-ini 样式文件的野兽——它很难看。我希望我可以使用 perl。)

于 2008-09-29T17:18:26.340 回答
1

我经常看到“我不能使用任何 Perl 模块”的限制,当它不是作业问题时,通常只是由于缺乏信息。是的,即使您可以使用 CPAN,也包含有关如何在没有 root 权限的情况下在本地安装 CPAN 模块的说明。另一种选择是获取 CPAN 模块的源代码并将其粘贴到您的程序中。

如果存在其他未说明的限制,例如磁盘空间不足会阻止安装(太多)附加文件,则这些都无济于事。

于 2008-09-30T07:25:30.890 回答
0

这似乎适用于我设置的与您的示例匹配的一些测试文件。以这种方式涉及 perl(插入 grep)可能会极大地损害性能,尽管......

## perl code to do some dirty work

for my $line (`grep 'X Y Z' myhugefile`) {
    chomp $line;
    my ($a, $b, $c, $d, $e) = split(/ /,$line);
    my $cmd = 'grep -P "' . $d . ' .+? ' . $e .'" otherfile';
    for my $from_otherfile (`$cmd`) {
        chomp $from_otherfile;
        my ($oa, $ob, $oc, $od) = split(/ /,$from_otherfile);
        print "$a $ob $oc\n";
    }
}

编辑:使用 tsee 的解决方案(上图),这是经过深思熟虑的。

于 2008-09-27T20:31:50.807 回答