Сценарий Bash, использующий gzip и bcftools, не хватает памяти из-за больших файлов

Этот bash-скрипт является частью конвейера, обрабатывающего заархивированный файл .vcf, содержащий геномы нескольких пациентов (это означает, что файлы имеют огромный размер даже в заархивированном виде, например, 3–5 ГБ).

Моя проблема в том, что мне постоянно не хватает памяти при запуске этого скрипта. Он запускается на виртуальной машине с высоким уровнем памяти GCP.

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

#!/bin/bash

for filename in ./*.vcf.gz; do
    [ -e "$filename" ] || continue 
    name=${filename##*/}
    base=${name%.vcf.gz}
    bcftools query -l "$filename" >> ${base}_list.txt
    for line in `cat ${base}_list.txt`; do 
        bcftools view -s "$line" "$filename" -o ${line}.vcf.gz
        gzip ${line}.vcf 
    done
done

person NHellmann    schedule 21.01.2021    source источник
comment
Можете ли вы указать, в какой строке у вас заканчивается память? Это bcftools query/view, gzip или for line in `cat ...` ?   -  person Socowi    schedule 22.01.2021
comment
Не имеет отношения к реальной проблеме; [ -e "$filename" ] скорее всего бесполезен. *.csv.gz перечисляет только существующие файлы и каталоги. -e проверяет, существует ли $filename. Если вы хотите убедиться, что $filename является файлом, а не каталогом, используйте -f.   -  person Socowi    schedule 22.01.2021
comment
@Socowi *.csv.gz перечисляет только существующие файлы и каталоги => нет, если шаблон не соответствует ни одному файлу (кроме shopt -s nullglob). В этом случае вы получите filename=*.csv.gz, и это причина -e теста IMO. Если имя файла должно указывать на файл, то лучше использовать -f test.   -  person xhienne    schedule 22.01.2021


Ответы (2)


Если у вас закончилась память при использовании bcftools query/view или gzip, поищите в руководстве параметры, которые могут уменьшить объем памяти. В случае gzip вы также можете переключиться на альтернативную реализацию. Вы даже можете рассмотреть возможность полного переключения алгоритма сжатия (zstd довольно хорош).

Однако у меня есть ощущение, что проблема может быть for line in `cat ${base}_list.txt`;. Весь файл ..._list.txt загружается в память еще до начала цикла. Кроме того, чтение строк таким образом имеет всевозможные проблемы, такие как разделение строк по пробелам, расширение глобусов, таких как *, и так далее. Используйте это вместо этого:

while read -r line; do 
    bcftools view -s "$line" "$filename" -o "$line.vcf.gz"
    gzip "$line.vcf"
done < "${base}_list.txt"

Кстати: вы уверены, что хотите, чтобы bcftools query -l "$filename" >> ${base}_list.txt добавлялось? Файл ${base}_list.txt будет увеличиваться при каждом выполнении скрипта. Попробуйте перезаписать файл, используя > вместо >>.
Однако в этом случае вам может вообще не понадобиться файл, так как вместо него можно использовать следующее:

bcftools query -l "$filename" |
while read -r line; do 
    bcftools view -s "$line" "$filename" -o "$line.vcf.gz"
    gzip "$line.vcf"
done
person Socowi    schedule 21.01.2021

Вы можете попробовать использовать split для каждого файла (постоянного размера), а затем разбить файл на части с помощью gzip.

https://man7.org/linux/man-pages/man1/split.1.html

person Community    schedule 21.01.2021