/ / Wyszukiwanie / czytanie innego pliku z awk na podstawie zawartości bieżącego pliku, czy to możliwe? - perl, search, shell, awk, interfejs wiersza poleceń

Czy można wyszukiwać / czytać inny plik z awk na podstawie zawartości bieżącego pliku? - perl, search, shell, awk, interfejs wiersza poleceń

Przetwarzam ogromny plik za pomocą (GNU) awk, (inne dostępne narzędzia to: narzędzia powłoki Linuksa, stara wersja Perla (> 5.0), ale nie można „zainstalować modułów”.

Mój problem: jeśli jakieś pole1, pole2, pole3 zawierają X, Y, Z, to muszę szukać pliku w innym katalogu, który zawiera pole4 i pole5 w jednym wierszu, i wstawić dane z znalezionego pliku do bieżącego wyjścia.

Na przykład.:

Rzeczywista linia pliku:

f1 f2 f3 f4 f5
X  Y  Z  A  B

Teraz muszę wyszukać inny plik (w innym katalogu), który zawiera np.

f1 f2 f3 f4
A  U  B  W

I napisz do STDOUT $0 z oryginalnego pliku i f2 i f3 z znalezionego pliku, a następnie przetworzyć następną linię oryginalnego pliku.

Czy można to zrobić? awk?

Odpowiedzi:

2 dla odpowiedzi № 1

Pozwolę sobie zacząć od stwierdzenia, że ​​opis problemu nie jest tak naprawdę pomocny.

Tak więc z twojego opisu rozumiem, że maszdwa pliki zawierające dane oddzielone białymi znakami. W pierwszym pliku chcesz dopasować pierwsze trzy kolumny do jakiegoś wzorca wyszukiwania. Jeśli zostanie znaleziony, chcesz znaleźć wszystkie linie w innym pliku, które zawierają czwartą i piątą kolumnę pasującej linii w pierwszym pliku. Z tych wierszy musisz wyodrębnić drugą i trzecią kolumnę, a następnie wydrukować pierwszą kolumnę pierwszego pliku, a drugą i trzecią drugą. Dobra, idzie:

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

W przeciwieństwie do rozwiązania innego plakatu, które zawiera wiele wywołań systemowych, nie wraca to do powłoki i dlatego powinno być bardzo szybkie.


1 dla odpowiedzi nr 2

To jest rodzaj pracy, która zmusiła mnie do przejściaawk to perl w pierwszej kolejności. Jeśli zamierzasz to osiągnąć, możesz łatwiej utworzyć skrypt powłoki, który tworzy skrypty awk do kwerendy, a następnie aktualizować w osobnych krokach.

(Napisałem taką bestię do czytania / aktualizowania plików w stylu windows-ini - jest brzydka. Chciałbym móc użyć perla.)


1 dla odpowiedzi nr 3

Często widzę ograniczenie „Nie mogę używać żadnych modułów Perla”, a gdy nie jest to pytanie domowe, często jest to spowodowane brakiem informacji. Tak, nawet możesz używać CPAN zawiera instrukcje dotyczące instalacji modułów CPAN lokalnie bez uprawnień administratora. Inną alternatywą jest pobranie kodu źródłowego modułu CPAN i wklejenie go do programu.

Nic z tego nie pomaga, jeśli istnieją inne, nieokreślone ograniczenia, takie jak brak miejsca na dysku, które uniemożliwia instalację (zbyt wielu) dodatkowych plików.


0 dla odpowiedzi nr 4

Wydaje się, że działa to w przypadku niektórych plików testowych, które ustawiam, pasując do twoich przykładów. Zaangażowanie perla w ten sposób (zaimplementowane za pomocą grep) prawdopodobnie zaszkodzi wydajności, chociaż ...

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

EDYTOWAĆ: Użyj rozwiązania tsee (powyżej), jest o wiele lepiej przemyślane.