Frage

Ich bin die Verarbeitung eine große Datei mit (GNU) awk, (andere Werkzeuge sind: Linux-Shell-Tools, einig alte (> 5.0) Version von Perl, können aber nicht installieren Module)

.

Mein Problem: wenn einige Feld1, Feld2, Field3 X enthält, Y, ZI für eine Datei in einem anderen Verzeichnis suchen muß, die field4 enthält, und field5 auf einer Linie, und setzen Sie auf die aktuelle Ausgabe einige Daten aus der gefundenen Datei.

Z. B:.

Die tatsächliche Dateizeile:

f1 f2 f3 f4 f5
X  Y  Z  A  B

Jetzt muß ich für eine andere Datei (in einem anderen Verzeichnis) suchen, die enthalten z.

f1 f2 f3 f4
A  U  B  W

Und schreiben Sie an STDOUT $0 aus der ursprünglichen Datei, und f2 und f3 aus der gefundenen Datei, dann die nächste Zeile der Originaldatei verarbeiten.

Ist es möglich, es mit awk zu tun?

War es hilfreich?

Lösung

Lassen Sie uns beginnen mit den Worten, dass die Problembeschreibung ist nicht wirklich so hilfreich. Das nächste Mal bitte einfach Genauer gesagt:. Vielleicht haben Sie heraus viel bessere Lösungen fehlt

Also von Ihrer Beschreibung, ich verstehe Sie zwei Dateien, die durch Leerzeichen getrennte Daten enthalten. In der ersten Datei, möchten Sie die ersten drei Spalten gegen einige Suchmuster entsprechen. Wenn sie gefunden wird, mögen Sie alle Zeilen in einer anderen Datei finden, die die vierte und fünfte und Spalte der passenden Zeile in der ersten Datei enthalten. Aus diesen Linien, müssen Sie die zweite und dritte Säule extrahieren und dann die erste Spalte der ersten Datei und die zweite und die dritte von der zweiten Datei drucken. Okay, hier geht:

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

Im Gegensatz zu einem anderen Lösung des Plakats, das viele Systemaufrufe enthält, das nicht an die Schale überhaupt nicht zurückfallen und damit viel schneller sein sollte.

Andere Tipps

Dies ist die Art von Arbeit, die mich bekam von awk zu bewegen, in erster Linie Perl. Wenn Sie dies erreichen werden, können Sie es tatsächlich einfacher finden einen Shell-Skript zu erstellen, die awk-Skript erstellt (s) abzufragen und dann in getrennten Schritten aktualisieren.

(Ich habe geschrieben solch ein Tier zum Lesen / Fenster-ini-Style-Dateien aktualisieren -.. Es ist hässlich Ich wünschte, ich Perl verwendet haben könnte)

Ich sehe oft die Einschränkung „ich keine Perl-Module verwenden können“, und wenn es keine Hausaufgaben Frage ist, ist es oft nur aufgrund eines Mangels an Informationen. Ja, auch können Sie CPAN verwenden die Anweisungen enthält, wie CPAN Module lokal zu installieren, ohne Root-Rechte mit . Eine weitere Alternative ist nur den Quellcode eines CPAN-Modul zu nehmen und es in Ihr Programm einfügen.

All dies hilft, wenn es andere, unausgesprochene, Einschränkungen, wie Mangel an Speicherplatz, den Einbau von (zu vielen) weitere Dateien zu verhindern.

Dies scheint, dass ich Ihre Beispiele passende Set für einige Testdateien aufzuarbeiten. Die Einbeziehung Perl auf diese Weise (mit grep zwischen) gehen ist wahrscheinlich der Leistung viel zu verletzen, aber ...

## 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";
    }
}

EDIT:. Verwenden tsee-Lösung (siehe oben), ist es viel mehr gut durchdacht

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top