Как извлечь из файла только первую строку, которая соответствует каждому шаблону? - PullRequest
0 голосов
/ 10 мая 2018

У меня есть текстовый файл, который выглядит как

Line_A 123
Line_A 456
Line_A 789
Line_B 123
Line_B 456
Line_B 789
Line_C 123
Line_C 456
Line_C 789

И справочный файл, который выглядит так:

 Line_A
 Line_B
 Line_C

Я хочу извлечь первую строку из текстового файла, который соответствует каждому имени в справочном файле, например:

Line_A 123
Line_B 123
Line_C 123

Пока что я могу получить только первую строку из первого матча с:

grep -A1 -w -f  reference.txt -m 1 file.txt

Может быть, мне нужен цикл for? ТИА

Ответы [ 3 ]

0 голосов
/ 10 мая 2018

еще awk

$ awk 'NR==FNR{a[$1];next} $1 in a{delete a[$1]; print}' reference file

Храните ссылки в наборе, когда видно в файле, напечатайте строку и удалите ссылку, поэтому будет напечатан только первый экземпляр.

0 голосов
/ 10 мая 2018

Еще один awk:

$ awk 'a[$1]++==1' ref file
Line_A 123
Line_B 123
Line_C 123

Прочитайте оба файла в указанном выше порядке, сосчитайте каждую строку в первом столбце и напечатайте, когда она будет видна во второй раз. Это не удастся, если в file есть строки, которых нет в reference. В этом случае используйте одно из других решений.

0 голосов
/ 10 мая 2018

Вы можете сделать это в Awk за один проход по файлам, если в списке аргументов вы сначала указали справочный файл:

awk 'FNR == NR { name[$1] = 0; }
     FNR != NR { for (i in name) if ($0 ~ i && name[i]++ == 0) { print $0; break; } }' \
    reference.txt file.txt

При вводе сэмплов это дает требуемый вывод.

Это довольно стандартная техника в Awk. Вы читаете первый файл, используя условие FNR == NR (номер строки файла равен общему номеру строки; значение true только для строк в первом файле) и сохраняете соответствующую информацию для последующего использования. Часто люди используют next в первой строке; оно работает. Это означает, что они могут избежать условие FNR != NR - мне нравится это для симметрии.

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

Именно так многие люди будут писать команду; это тоже работает.

awk 'FNR == NR { name[$1] = 0; next }
     { for (i in name) if ($0 ~ i && name[i]++ == 0) { print $0; break; } }' \
    reference.txt file.txt

Обе версии кода здесь ищут имя в любом месте строки; если вы строго хотите соответствовать $1 второго (или последующих) файлов, вы можете изменить условия (в действительности, упростить их). И karakfa показывает удаление совпадений при их совпадении (вместо увеличения счетчика), что лучше для производительности, поскольку вам не нужно продолжать сопоставлять то, что больше не актуально , Тем не менее, код, показанный здесь, было бы проще адаптировать для отображения второй, третьей или последней записи для данного имени (обработка второй или третьей включает изменение от 0 до 1 или 2; обработка «последнего» требует более существенных изменений).

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