根据当前文件的内容从awk搜索/读取另一个文件,这可能吗?

时间:2020-03-06 14:49:50  来源:igfitidea点击:

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

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

例如。:

实际文件行:

f1 f2 f3 f4 f5
X  Y  Z  A  B

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

f1 f2 f3 f4
A  U  B  W

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

是否可以用" awk"做到这一点?

解决方案

这似乎适用于我根据示例设置的一些测试文件。但是,以这种方式(与grep插入)一起使用perl可能会严重损害性能,但是...

## 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的解决方案(以上),这是经过深思熟虑的。

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

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

#!/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上,因此应该足够快。

这是使我首先从awk转到perl的工作类型。如果要完成此任务,实际上可能会发现创建外壳脚本更容易,该外壳脚本会创建要查询的awk脚本,然后在单独的步骤中进行更新。

(我写了这样的野兽来读取/更新Windows-ini风格的文件,这很丑陋。我希望我可以使用perl。)

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

如果还有其他未说明的限制(例如,磁盘空间不足,无法安装(过多)添加文件),则所有这些都无济于事。