Я думаю, это то, что вы ищете:
- читать строки ввода из STDIN
- разбить на первую часть + клавиша
- , если мы невидимый ключ перед
- откройте новый файл для записи, используя индекс в имени файла
- сохраните дескриптор файла в хэше, используя ключ.
- увеличьте индекс на один
- получить дескриптор файла из хэша с ключом и записать в него первую часть
- закрыть все дескрипторы открытого файла, когда мы закончим
#!/usr/bin/perl
use strict;
use warnings;
my $index = 1;
my %seen;
while (<STDIN>) {
chomp;
my($start, $key) = /^(\S+\s+\S+)\s+(.+)\s*$/;
unless ($seen{$key}) {
# new key detected, we need to open new file
open(my $fh, '>', "File_${index}.txt")
or die "can't open new file: $!\n";
$seen{$key} = $fh;
$index++;
}
my $fh = $seen{$key};
print $fh "${start}\n";
}
# close files
close $_ foreach (values %seen);
exit 0;
Тестовый прогон:
$ perl dummy.pl <dummy.txt
$ cat File_1.txt
XIGO XIGO_24480
XIGO XIGO_24481
$ cat File_2.txt
XOLO XOLO_Z1E01
XOLO XOLO_Z1G01
$ cat File_3.txt
YORK TYo_0GT393
YORK TYo_0GT394
ПРИМЕЧАНИЕ: для полноты картины: приведенное выше решение приведет к ошибке too many open files
на стандартном компьютере с Linux, если ваш ввод более ~1000 ключей.Вам нужно будет использовать ulimit
, чтобы увеличить лимиты, или предварительно отсортировать данные, чтобы использовать оптимизированную версию ниже.Или сохраните все данные в памяти и запишите файлы после окончания цикла.
РЕДАКТИРОВАТЬ: это можно оптимизировать, если вы уверены, что ключи не повторяются ввходной файл, например,
my $fh;
while (<STDIN>) {
chomp;
my($start, $key) = /^(\S+\s+\S+)\s+(.+)\s*$/;
unless ($seen{$key}++) {
# new key detected, we need to open new file
if ($fh) {
close($fh) or die "close: $!\n";
}
open($fh, '>', "File_${index}.txt")
or die "can't open new file: $!\n";
$index++;
}
print $fh "${start}\n";
}
# make sure to close last open file
close($fh) or die "close: $!\n";
Я не знаю, как выглядят ваши реальные входные данные, но если порядок вывода не имеет значения, вы можете предварительно отсортировать входные данные в bash для этого оптимизированноговерсия с:
$ sort -t $'\t' -k 3 dummy.txt | perl dummy.pl
EDIT2 , если вы хотите сохранить исходный split()
подход:
# remove trailing whitespace
s/\s+$//;
my($FID, $IID, $key) = split('\t', $_);
...
print $fh "${FID}\t${IID}\n";