Возможно ли поиск / чтение другого файла из awk на основе содержимого текущего файла?

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

Моя проблема: если некоторые field1, 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?

Не уверен, что могу понять, что вы пытаетесь сделать, на основе вашего примера - не могли бы вы немного прояснить это? По каким критериям вы находите другой файл? Почему вы выводите f2 и f3 из второго файла или это фиксированное требование?

Ben 28.09.2008 00:17
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
1 480
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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 $oc\n";
    }
}

Обновлено: Воспользуйтесь решением tsee (см. Выше), оно гораздо более продуманное.

Использование Perl совершенно не вредит производительности! Вызов команд оболочки с использованием обратных кавычек из perl (как и вы) снижает производительность. Если вы воспользуетесь типичной для оболочки идиомой, состоящей в том, чтобы пропустить вещи через множество программ или вызвать множество дополнительных процессов, вы снизите производительность.

tsee 29.09.2008 11:00

Вы совершенно правы, це. Я имел в виду, что использование Perl именно таким образом ухудшит производительность. Ваш правильно написанный сценарий намного лучше.

Adam Bellaire 29.09.2008 15:40

Извините за такую ​​резкость, я неправильно понял второе предложение вашего сообщения. Ваше здоровье,

tsee 29.09.2008 20:08
Ответ принят как подходящий

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

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

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

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

Извините за неправильное указание. Я попробую ваше решение на работе. Один вопрос: как решить, что имя другого файла (t.txt в вашем ответе) неизвестно: поэтому мне нужно найти файл, который соответствует моим критериям?

Zsolt Botykai 29.09.2008 12:22

Каковы ваши критерии для имени файла? Что вам следует сделать: используйте File :: Find. Это модуль для рекурсивного просмотра каталогов. Он был в Perl 5.0, так что вы можете спокойно его использовать.

tsee 29.09.2008 14:16

Это намного лучшее решение, чем мой хак, который загружал бы все содержимое обоих greps в память и (вероятно) был бы очень медленным. Было бы неплохо увидеть добавление File :: Find для полного решения.

Adam Bellaire 29.09.2008 15:35

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

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

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

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

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

Zsolt Botykai 10.10.2008 00:46

Другие вопросы по теме