Объединить куски из нескольких файлов

Мне нужно объединить куски из нескольких, но больших файлов. Каждая строка содержит имя файла и байтовые смещения.

# 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 , но это будет многократно открывать один и тот же файл, замедляя процесс. Единственным решением, о котором я думал, было кодирование программы, которая искала начало каждого фрагмента и печаталась до конца, открывая каждый файл только один раз.

Есть ли у вас предложения?

2 Solutions collect form web for “Объединить куски из нескольких файлов”

Что-то вроде этого 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(); 

С zsh :

 zmodload zsh/mapfile while read -rfbe; 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 -rfbe; do [[ -f $f ]] && head -c "$((e-b+1))" < "$f" <#(($b)) done < list.txt > merged 

Настройка PATH таким образом, чтобы head была встроенной ksh93 (даже если нет каталога /opt/ast/bin ). <#((n)) является интерфейсом ksh93 для lseek .

 PATH=/opt/ast/bin:$PATH export PATH while read -rfbe; do [[ -f $f ]] && head -c "$((e-b+1))" -s "$b" < "$f" done < list.txt > merged 

ksh93 есть опция -s для пропуска данных (для обычных файлов используется lseek ). Он будет работать до тех пор, пока ksh93 будет построен с включенной head .

  • Как добавить каждый элемент в список с помощью цикла?
  • Значение bash $ LINE не отображается, если определено как val = `$ LINE`
  • Цветной вывод из сценария Bash
  • не может скопировать более 29 файлов на целевой сервер, используя сценарий оболочки
  • как заменить от A до B комбад?
  • скрипт bash, не выполняемый cron
  • Как использовать переменную для строки кода скрипта?
  • Выполнение chown в скрипте bash вызывает ошибки
  • команды curl и grep выводятся в новую переменную
  • Как передать содержимое файла параметру / параметру функции
  • Что означает `{{(выход 1); выход 1; }; } `означает?
  • Bash выберите вариант, не нажимая enter.
  • Linux и Unix - лучшая ОС в мире.