Объединение файлов на основе общих данных

Я бы использовал для этого Perl-скрипт. Я придумал это:

#!/usr/bin/perl

# usage: thisscript linenumberslist.txt contentsfile

unless (open(IN, $ARGV[0])) {
        die "Can't open list of line numbers file '$ARGV[0]'\n";
}
my %linenumbers = ();
while (<IN>) {
        chomp;
        $linenumbers{$_} = 1;
}

unless (open(IN, $ARGV[1])) {
        die "Can't open contents file '$ARGV[1]'\n";
}
$. = 0;
while (<IN>) {
        print if defined $linenumbers{$.};
}

exit;

Это сначала считывает список номеров строк, которые нас интересуют, в ассоциативный массив, где номера строк являются ключом.chompудаляет новую строку в конце строки, $_— это сама строка.

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

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

Вероятно, это можно было бы написать намного больше в стиле "perl", но я предпочитаю, чтобы это было немного более читабельным.

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

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

0
19.04.2021, 19:30
1 ответ

Предположим, что два файла отсортированы по полю соединения (по первой запятой -по полю с разделителями ), тогда вы можете использовать

$ join -t, file1 file2
799001,8_802,3122,627654,567765,v567575

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

$ join -t, <( sort file1 ) <( sort file2 )
799001,8_802,3122,627654,567765,v567575

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

$ awk -F, 'BEGIN { OFS = FS } NR == FNR { key[$1] = $0; next } ($1 in key) { k = $1; sub("^[^,]*,",""); print key[k], $0 }' file1 file2
799001,8_802,3122,627654,567765,v567575

Это похоже на то, что у вас есть, но сохраняет всю строку в ассоциативном массиве.Затем оператор printвыводит сохраненное значение из первого файла по строке из второго файла, кроме первого поля, которое удаляется с помощью sub().

Переменная kво второй части кода необходима, так как вызов sub()изменяет значение $1.

Вызов sub()предполагает, что FSявляется запятой. Чтобы вместо этого использовать фактическое значение FS, каким бы оно ни было, используйте

sub("^[^" FS "]*" FS,"")

вместо этого. Это будет работать при условии, что FSявляется одним символом.

Если вы хотите использовать свои предварительные знания о количестве полей во втором файле, вы можете избежать несколько беспорядочного вызова sub()и переменной kс помощью

$ awk -F, 'BEGIN { OFS = FS } NR == FNR { key[$1] = $0; next } ($1 in key) { print key[$1], $2, $3 }' file1 file2
799001,8_802,3122,627654,567765,v567575
0
28.04.2021, 22:51

Теги

Похожие вопросы