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