여러 개의 대용량 파일에서 청크를 병합해야 합니다. 각 줄에는 파일 이름과 바이트 오프셋이 포함됩니다.
# file begin end
foo/a 11970 12010
foo/a 22995 23035
foo/b 45090 45130
foo/b 46035 46075
foo/b 48150 48190
foo/c 16200 16240
foo/c 17550 17590
foo/c 18540 18580
foo/c 26730 26770
foo/c 34245 34285
tail -c
및 를 사용하여 추출을 수행할 수 있지만 head -c
이렇게 하면 동일한 파일이 여러 번 다시 열리므로 프로세스 속도가 느려집니다. 제가 생각해낸 독특한 해결책은 각 블록의 시작 부분을 찾아 끝까지 인쇄하고 각 파일을 한 번만 여는 프로그램을 작성하는 것입니다.
의견 있으십니까?
답변1
Perl은 이와 같이 작동해야합니다. 적절한 경우 파일 이름을 바꾸십시오.
#!/usr/bin/env perl
use strict;
use warnings;
use IO::Handle;
open(my $list_fh, '<', 'somefile') or die "Failed to open list file: $!";
open(my $out_fh, '>', 'outfile') or die "Failed to open out file: $!";
my $merge_fh = IO::Handle->new();
my $cur_fname = q{};
my $buff;
while ( my $line = <$list_fh> ) {
next if $line =~ /^\s?#/;
chomp($line);
my ($fname, $begin, $end) = split(/\s+/, $line);
if ( $cur_fname ne $fname ) {
$merge_fh->close() if $merge_fh->opened();
open($merge_fh, '<', $fname) or die "Failed to open file: $!";
$cur_fname = $fname;
}
seek($merge_fh, $begin, 0);
read($merge_fh, $buff, $end - $begin);
print {$out_fh} $buff or die "Failed to write to $cur_fname: $!";
}
$merge_fh->close();
$out_fh->close();
$list_fh->close();
답변2
그리고 zsh
:
zmodload zsh/mapfile
while read -r f b e; do
[ -f $f ] && printf %s ${${mapfile[$f]}[b+1,e+1]}
done < list.txt > merged
하지만 너무 열정적이지는 마세요. $mapfile
사용 mmap
하지만 메모리의 전체 파일을 읽습니다. ( info zsh 'The zsh/mapfile Module'
자세히보다).
그리고 ksh93
:
PATH=/opt/ast/bin:$PATH export PATH
while read -r f b e; do
[[ -f $f ]] && head -c "$((e-b+1))" < "$f" <#(($b))
done < list.txt > merged
ksh93 내장 명령이 되도록 PATH를 설정합니다 head
(디렉토리가 없더라도 /opt/ast/bin
). <#((n))
ksh93의 프런트 엔드입니다 lseek
.
PATH=/opt/ast/bin:$PATH export PATH
while read -r f b e; do
[[ -f $f ]] && head -c "$((e-b+1))" -s "$b" < "$f"
done < list.txt > merged
ksh93
선택적으로 데이터를 head
건너뜁니다 -s
( lseek
일반 파일에 내부적으로 사용됨). ksh93
내장된 함수를 사용하여 구축했다면 작동할 것 입니다 head
.