Поиск / чтение другого файла из awk на основе содержимого текущего файла, возможно ли это? - PullRequest
2 голосов
/ 27 сентября 2008

Я обрабатываю огромный файл с помощью (GNU) awk, (другие доступные инструменты: инструменты оболочки Linux, некоторые старые (> 5.0) версии Perl, но не могут устанавливать модули).

Моя проблема: если некоторые поля field1, field2, field3 содержат X, Y, ZI должен найти файл в другом каталоге, содержащий 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?

Ответы [ 4 ]

2 голосов
/ 29 сентября 2008

Позвольте мне начать с того, что описание вашей проблемы не очень полезно. В следующий раз, пожалуйста, будьте более конкретны: Вы можете упустить гораздо лучшие решения.

Итак, из вашего описания я понимаю, что у вас есть два файла, которые содержат разделенные пробелами данные. В первом файле вы хотите сопоставить первые три столбца с некоторым шаблоном поиска. Если найдено, вы хотите найти все строки в другом файле, которые содержат четвертый и пятый столбец соответствующей строки в первом файле. Из этих строк необходимо извлечь второй и третий столбец, а затем распечатать первый столбец первого файла, а второй и третий - из второго файла. Хорошо, здесь идет:

#!/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 голос
/ 30 сентября 2008

Я часто вижу ограничение «Я не могу использовать любые модули Perl», и когда это не домашнее задание, это часто просто из-за недостатка информации. Да, даже если вы можете использовать CPAN содержит инструкции о том, как устанавливать модули CPAN локально, не имея привилегий root. Другой вариант - просто взять исходный код модуля CPAN и вставить его в свою программу.

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

1 голос
/ 29 сентября 2008

Это тип работы, который заставил меня перейти с awk на perl. Если вы собираетесь выполнить это, вам может оказаться проще создать сценарий оболочки, который создает сценарии awk для запроса, а затем обновляет его в отдельных шагах.

(Я написал такого зверя для чтения / обновления файлов в стиле windows-ini - это ужасно. Хотелось бы, чтобы я использовал perl.)

0 голосов
/ 28 сентября 2008

Кажется, это работает для некоторых тестовых файлов, которые я настроил в соответствии с вашими примерами. Подобное использование 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 (выше), это гораздо более продуманно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...