현재 파일의 내용을 기반으로 AWK에서 다른 파일 검색/읽기 가능합니까?
-
02-07-2019 - |
문제
(GNU)로 거대한 파일을 처리하고 있습니다. awk
, 다른 도구는 다음과 같습니다. Linux 쉘 도구, 일부 구식 (> 5.0) 버전의 Perl이지만 모듈을 설치할 수 없습니다).
내 문제 : 일부 Field1, Field2, Field3에 x, y, zi가 하나의 줄에 Field4를 포함하는 다른 디렉토리의 파일을 검색하고 찾은 파일에서 현재 출력에 일부 데이터를 삽입해야합니다.
예 :
실제 파일 라인 :
f1 f2 f3 f4 f5
X Y Z A B
이제 다른 파일 (다른 디렉토리)을 검색해야합니다.
f1 f2 f3 f4
A U B W
그리고 stdout에 편지를 씁니다 $0
원본 파일에서 f2
그리고 f3
찾은 파일에서 원본 파일의 다음 줄을 처리하십시오.
할 수 있습니까? awk
?
해결책
문제 설명이 실제로 그렇게 도움이되지 않는다고 말하면서 시작하겠습니다. 다음에 더 구체적으로 말하십시오. 훨씬 더 나은 솔루션을 놓치게 될 수 있습니다.
따라서 귀하의 설명에서, 나는 당신이 공백으로 구분 된 데이터를 포함하는 두 개의 파일이 있다는 것을 알고 있습니다. 첫 번째 파일에서는 처음 세 열을 일부 검색 패턴과 일치 시키려고합니다. 발견되면 첫 번째 파일에서 일치하는 줄의 네 번째 및 다섯 번째 열이 포함 된 다른 파일에서 모든 줄을 찾으려고합니다. 이 라인에서 두 번째 및 세 번째 열을 추출한 다음 첫 번째 파일의 첫 번째 열을 인쇄하고 두 번째 파일과 세 번째는 두 번째 파일에서 인쇄해야합니다. 좋아, 여기 간다 :
#!/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
많은 시스템 호출이 포함 된 다른 포스터의 솔루션과 달리, 이것은 전혀 껍질로 돌아 가지 않으므로 충분히 빠릅니다.
다른 팁
이것은 처음에 Awk에서 Perl로 이동하게 한 일의 유형입니다. 이를 달성하려면 실제로 awk 스크립트를 생성하는 쉘 스크립트를 작성하고 별도의 단계로 업데이트하는 것이 더 쉬울 수 있습니다.
(Windows-Ini 스타일 파일을 읽고/업데이트하기위한 그런 짐승을 썼습니다. 추악합니다. Perl을 사용할 수 있었으면 좋겠다.)
나는 종종 "내가 Perl 모듈을 사용할 수 없다"는 제한을 본다. 그리고 그것이 숙제가 아닌 경우, 종종 정보 부족 때문이다. 예, CPAN을 사용할 수 있습니다 루트 권한없이 CPAN 모듈을 로컬로 설치하는 방법에 대한 지침이 포함되어 있습니다. 또 다른 대안은 단지 CPAN 모듈의 소스 코드를 가져 와서 프로그램에 붙여 넣는 것입니다.
이 중 어느 것도 (너무 많은) 추가 파일의 설치를 방지하는 디스크 공간 부족과 같은 다른, 언급되지 않은 제한이있는 경우에 도움이되지 않습니다.
이것은 예제와 일치하는 일부 테스트 파일에서 작동하는 것 같습니다. 이런 식으로 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의 솔루션 (위)을 사용하면 훨씬 더 잘 생각됩니다.