/ / Пошук / читання іншого файлу з awk на основі вмісту поточного файлу, чи можливо це? - perl, search, shell, awk, інтерфейс командного рядка

Пошук / читання іншого файлу з awk на основі вмісту поточного файлу, чи можливо це? - perl, search, shell, awk, інтерфейс командного рядка

Я обробляю величезний файл з (GNU) awkІнші доступні засоби: засоби оболонки Linux, деякі старі (> 5.0) версії Perl, але не можуть встановлювати модулі.

Моя проблема: якщо деякі поля1, field2, field3 містять X, Y, Z я повинен шукати файл в іншому каталозі, який містить field4, і field5 на одному рядку, і вставити деякі дані з знайденого файлу на поточний вивід.

Напр .:

Фактичний рядок файлу:

f1 f2 f3 f4 f5
X  Y  Z  A  B

Тепер мені потрібно шукати інший файл (в іншому каталозі), який містить напр.

f1 f2 f3 f4
A  U  B  W

І напишіть на STDOUT $0 з вихідного файлу, і f2 і f3 з знайденого файлу, потім обробляти наступний рядок вихідного файлу.

Чи можливо це зробити awk?

Відповіді:

2 для відповіді № 1

Дозвольте мені почати, сказавши, що опис вашої проблеми не дуже корисний. Наступного разу, будь ласка, будьте більш конкретними.

Так що з вашого опису, я розумію, у вас єдва файли, які містять дані, розділені пробілами. У першому файлі потрібно встановити відповідність перших трьох стовпчиків певному шаблону пошуку. Якщо знайдено, ви хочете знайти всі рядки в іншому файлі, які містять четвертий і п'ятий стовпці відповідного рядка у першому файлі. З цих рядків потрібно витягти другий і третій стовпець, а потім друкувати перший стовпець першого файлу, другий і третій з другого файлу. Гаразд, тут:

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

На відміну від іншого рішення плаката, який містить безліч системних викликів, це зовсім не повертається до оболонки і тому має бути досить швидким.


1 для відповіді № 2

Це той вид роботи, який змусив мене перейтиawk в першу чергу. Якщо ви збираєтеся виконати це, вам, можливо, буде легше створити скрипт оболонки, який створює скрипти awk для запиту, а потім оновлювати окремо.

(Я написав такого звіра, щоб читати / оновлювати файли стилів windows-ini - це непривабливо.


1 для відповіді № 3

Я часто бачу обмеження "я не можу використовувати будь-які модулі Perl", і коли це не питання домашнього завдання, це часто просто через відсутність інформації. Так, навіть ви можете використовувати CPAN містить інструкції щодо локального встановлення CPAN-модулів без привілеїв root. Інша альтернатива - просто взяти вихідний код модуля CPAN і вставити його у вашу програму.

Нічого з цього не допомагає, якщо є інші, невстановлені обмеження, такі як відсутність дискового простору, що перешкоджає встановленню (занадто багато) додаткових файлів.


0 для відповіді № 4

Це, здається, працює для деяких тестових файлів, які я налаштував відповідно до ваших прикладів. Включення 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 $ocn";
}
}

EDIT: Використовуйте це рішення (вище), це набагато більш продумане.