문제

(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의 솔루션 (위)을 사용하면 훨씬 더 잘 생각됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top