2

(GNU)awkで巨大なファイルを処理しています (他の利用可能なツールは、Linux シェル ツール、古い (>5.0) バージョンの Perl ですが、モジュールをインストールできません)。

私の問題: field1、field2、field3 に X、Y、ZI が含まれている場合、field4 と field5 を 1 行に含む別のディレクトリでファイルを検索し、見つかったファイルのデータを現在の出力に挿入する必要があります。

例えば:

実際のファイル行:

f1 f2 f3 f4 f5
X  Y  Z  A  B

ここで、たとえば別のファイルを (別のディレクトリで) 検索する必要があります。

f1 f2 f3 f4
A  U  B  W

元のファイルから STDOUT に書き込み、見​​つかったファイルから$0、元のファイルの次の行を処理します。f2f3

でそれを行うことは可能awkですか?

4

4 に答える 4

2

あなたの問題の説明はあまり役に立たないということから始めましょう。次回は、もっと具体的に教えてください。もっと良い解決策を見逃す可能性があります。

あなたの説明から、空白で区切られたデータを含む 2 つのファイルがあることがわかりました。最初のファイルでは、最初の 3 列を検索パターンと照合します。見つかった場合は、最初のファイルの一致する行の 4 番目と 5 番目の列を含む別のファイルのすべての行を検索します。これらの行から、2 番目と 3 番目の列を抽出し、最初のファイルの 1 番目の列と 2 番目のファイルの 2 番目と 3 番目の列を出力する必要があります。さて、ここに行きます:

#!/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

多くのシステムコールを含む別のポスターのソリューションとは異なり、これはシェルにまったくフォールバックしないため、十分に高速になるはずです。

于 2008-09-29T07:19:02.943 に答える
1

これは、私が最初にawkからperlに移行したタイプの作業です。これを実現する場合は、実際には、クエリを実行して別の手順で更新するawkスクリプトを作成するシェルスクリプトを作成する方が簡単な場合があります。

(私はwindows-iniスタイルのファイルを読んだり更新したりするためにそのような獣を書いた-それは醜い。perlを使えたらよかったのに。)

于 2008-09-29T17:18:26.340 に答える
1

「Perl モジュールは使用できません」という制限をよく目にしますが、それが宿題の質問でない場合は、多くの場合、情報が不足していることが原因です。はい、CPAN を使用することもできます。root権限を持たずに CPAN モジュールをローカルにインストールする方法についての説明が含まれています。もう 1 つの方法は、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 に答える