我正在使用(GNU)awk
处理一个巨大的文件,(其他可用的工具是:Linux shell工具,一些旧的(> 5.0)版本的Perl,但无法安装模块)。< / p>
我的问题:如果某些field1,field2,field3包含X,Y,ZI必须在另一个目录中搜索包含field4和field5的文件,并将找到的文件中的一些数据插入当前输出。
E.g:
实际文件行:
f1 f2 f3 f4 f5
X Y Z A B
现在我需要搜索另一个文件(在另一个目录中),其中包含例如
f1 f2 f3 f4
A U B W
从原始文件写入STDOUT $0
,从找到的文件写入f2
和f3
,然后处理原始文件的下一行。
是否可以使用awk
?
答案 0 :(得分: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,因此应该足够快。
答案 1 :(得分:1)
这是让我从一开始就从awk迁移到perl的工作类型。如果您要完成此任务,您实际上可能会发现创建一个shell脚本更容易,该脚本创建awk脚本以进行查询,然后在单独的步骤中进行更新。
(我写过这样一个用于阅读/更新windows-ini风格文件的野兽 - 它很丑陋。我希望我可以使用perl。)
答案 2 :(得分:1)
我经常看到限制“我不能使用任何Perl模块”,当它不是一个家庭作业问题时,通常只是由于缺乏信息。 Yes, even you can use CPAN包含有关如何在没有root权限的情况下在本地安装CPAN模块的说明。另一种方法是获取CPAN模块的源代码并将其粘贴到您的程序中。
如果存在其他未声明的限制,例如缺少磁盘空间以防止安装(太多)其他文件,这些都没有任何帮助。
答案 3 :(得分: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的解决方案(上图),它更经过深思熟虑。