Один zcat несколько экстрактов с массивами идентификаторов - PullRequest
0 голосов
/ 26 мая 2020

У меня много gz-архивов размером более ГБ, которые я не могу распаковать из-за недостатка места на диске. Каждый архив имеет один определенный c идентификационный номер (например, test365.gz) и такую ​​структуру:

         1    1    2 1
##########                 Name:     ZINC000077407198
@<TRIPOS>MOLECULE
 ZINC000077407198      none
@<TRIPOS>ATOM
      1 C1          5.7064    -2.3998   -12.0246 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000099999999
@<TRIPOS>MOLECULE
 ZINC000099999999      none
@<TRIPOS>ATOM
      1 C1         -2.0084    -5.2055   -12.9609 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077402345
@<TRIPOS>MOLECULE
 ZINC000077402345     none
@<TRIPOS>ATOM
      1 C1          6.5657    -1.5531   -15.3414 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077407198
@<TRIPOS>MOLECULE
 ZINC000077407198      none
@<TRIPOS>ATOM
      1 C1          3.6696    -1.8305   -14.6766 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000012345678
@<TRIPOS>MOLECULE
 ZINC000012345678      none
@<TRIPOS>ATOM
      1 C1          4.5368    -0.8182   -17.4314 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077407100
@<TRIPOS>MOLECULE
 ZINC000077407100      none
@<TRIPOS>ATOM
      1 C1          1.4756    -2.2562   -14.0852 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077407198
@<TRIPOS>MOLECULE
 ZINC000077407198      none
@<TRIPOS>ATOM
      1 C1          6.1712    -0.8991   -16.4096 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077407198
@<TRIPOS>MOLECULE
 ZINC000077407198      none
@<TRIPOS>ATOM

Количество строк между определенным блоком ###### является переменным.

У меня есть список идентификаторов для ZIN C сущностей + целевой архив:

test365/    ZINC000077407198
test227/    ZINC000009100000
test365/    ZINC000077407100
... 

Сейчас я использую:

zcat test365.gz | sed -n '/##########                 Name:     ZINC000077407100/,/##########                 Name:/p' > ZINC000077407100.out

и получаю:

##########                 Name:     ZINC000077407100
@<TRIPOS>MOLECULE
 ZINC000077407100      none
@<TRIPOS>ATOM
      1 C1          1.4756    -2.2562   -14.0852 C.3        1  LIG1  -0.1500
@<TRIPOS>BOND
     1    1    2 1
##########                 Name:     ZINC000077407198

Что нормально работает. Если для ZINC000077407100 есть N блоков, я извлекаю N блоков на zcat и не возражаю против строки, начинающейся с #####.

Проблема в том, что мне нужно прочитать архив N раз для N идентификаторов / ZINC_NUMBER Мне нужна информация для. И это занимает много времени, поскольку у меня есть тысячи для извлечения.

Итак, я хотел бы найти способ передать массив или список идентификаторов / ZINC_NUMBER для вывода чтения zcat в несколько разных файлов в зависимости от идентификаторы в массиве / списке.

Другими словами, я хотел бы выполнить однократное чтение с помощью zcat и извлечь данные для набора идентификаторов, а не только для одного.

Спасибо за вашу помощь!

Ответы [ 2 ]

1 голос
/ 26 мая 2020

На OP требуется обработка большого объема данных (миллионы строк, несколько ГБ данных и необходимость извлекать данные о сотнях элементов). Технически возможно обойтись современным bash, но вряд ли он будет хорошо работать. Здесь лучше подойдет лучший скриптовый движок.

Возможное решение bash / awk, представленное здесь. Он просканирует каждый файл, на который есть ссылка, и извлечет все выбранные теги за один проход. Обратите внимание, что списки «тегов» будут сканироваться несколько раз, но подразумевается, что это разумный размер. *, Javascript или ваш любимый инструмент для обработки текста. Протестировано на выборке данных.

0 голосов
/ 26 мая 2020

Кажется, что каждая запись, начинающаяся с ##########, всегда имеет 6 строк. В этом случае было бы намного проще и эффективнее использовать grep -A7 вместо sed -n /##.../,/##.../p. Я полагаю, вы распечатали только последующий заголовок, так как это было проще (по крайней мере, при использовании sed). Поэтому я исключил последующий заголовок в этом ответе (grep -A6 вместо grep -A7).

grep можно указать список шаблонов для поиска. Это делается с помощью опции -f. Список шаблонов можно сгенерировать из вашего файла. Сначала сгруппируйте по имени архива (например, test365), а затем распечатайте все шаблоны для этого архива. Здесь мы используем awk. Нулевой байт разделяет разделы шаблона для каждого архива.

Чтобы предотвратить ложные срабатывания (и, возможно, немного ускорить поиск), мы ищем только полные строки, а не подстроки. Для ускорения мы установили LC_ALL=C. Вы также можете обнаружить, что zgrep быстрее, чем zcat | grep.

Следующий сценарий распаковывает каждый архив не более одного раза.

awk -v prefix='##########                 Name:     ' '
  {a[$1]=a[$1] "\n" prefix $2}
  END {for (k in a) print k a[k] "\0"}
' /path/to/your/list.txt |
while IFS=$'\n' read -r -d '' archive patterns; do
  LC_ALL=C zgrep -A6 -Fxf <(printf %s "$patterns") "${archive/\//.gz}"
  # TODO do something with the output for this archive
done

В приведенном выше сценарии я преобразовал test365/ из ваш список до test365.gz автоматически. Я не знаю вашу структуру каталогов. Если вам нужно что-то другое, адаптируйте последний аргумент zgrep. $archive выполняет итерацию по первому столбцу вашего ( сгруппированного ) списка (, то есть каждый архив указан только один раз ).

Из вашего примера кода кажется например, вы хотите создать отдельный файл для каждого шаблона. Для этого замените корпус l oop сверху на

zgrep ... > /tmp/zincfound
while IFS= read -r pattern; do
    grep -A6 -Fx "$pattern" /tmp/zincfound > "${pattern##* }.out" 
done <<< "$patterns"
rm /tmp/zincfound
...