【问题标题】:Single zcat multiple extracts with IDs arrays带有 IDs 数组的单个 zcat 多个提取
【发布时间】:2020-09-12 17:57:32
【问题描述】:

我有许多 GB+ 大小的 gz 档案,由于磁盘空间的原因,我无法解压缩。每个档案都有一个特定的标识号(例如 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

###### 定义块之间的行数是可变的。

我有一个 ZINC 实体 + 目标档案的标识符列表:

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 个块,我会在 zcat 上提取 N 个块,并且不介意以 ##### 开头的行。

问题是我需要为 N 个标识符 / ZINC_NUMBER 读取存档 N 次我想要的信息。而且要花很多时间,因为我要提取数千个。

所以我想找到一种方法来传递一个数组或标识符列表/ZINC_NUMBER,以根据数组/列表中的标识符将 zcat 读取输出到几个不同的文件。

换句话说,我想使用 zcat 进行单次读取,并为一组标识符提取数据,而不仅仅是一个。

感谢您的帮助!

【问题讨论】:

  • 你的问题很难理解。我看到test365.gz 是一个 GB+ 文件。您是否要在该文件中查找数百个文本块并将每个文本块输出到不同的文件?或者您想在数百个其他文件中搜索每个大至test365.gz 的数百个文本块?或者是别的什么?顺便说一句,恕我直言,用sed 搜索很少是解决方案,我怀疑awk 可能会更好。
  • 您确定此处发布的sed 命令对您有用吗?首先,我期待 -n 选项,因为您说您无法解压缩整个文件。然后 sed 命令有 for s/a/,/b/p 这对我来说会引发错误。你的意思是sed -n '/a/,/b/p'
  • 您是否尝试将大文件拆分为多个以 ID 为关键字的小文件(例如 ZINC000077407100.out)。您需要每个 ID 的文件,还是一个小子集(将检索多少个 ID,与文件中有多少个 ID)?
  • 此外,“sed”命令将复制文件的所有内容,包括不包含该模式的行。这将比原来占用更多的空间。
  • 最后评论:请澄清行尾在哪里(输入似乎环绕)。

标签: python bash zcat


【解决方案1】:

似乎每个以########## 开头的条目总是有 6 行。在这种情况下,使用grep -A7 而不是sed -n /##.../,/##.../p 会更容易和更有效。我想您只打印了后续标题,因为这样更容易(至少在使用sed 时)。因此,我排除了此答案中的后续标头(grep -A6 而不是grep -A7)。

grep 可以给出要搜索的模式列表。这是通过-f 选项完成的。可以从您的文件中生成模式列表。首先按存档名称分组(例如test365),然后打印该存档的所有模式。在这里,我们使用awk 来执行此操作。一个空字节分隔每个存档的模式部分。

为了防止误报(并可能加快搜索速度),我们只搜索完整的行而不是子字符串。为了加快速度,我们设置了LC_ALL=C。您可能还会发现zgrepzcat | 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 遍历您的(分组)列表的第一列(也就是说,每个存档只列出一次)。

从您的示例代码看来,您希望为每个模式生成一个单独的文件。为此,请将上面的循环体替换为

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

【讨论】:

  • 感谢考虑 Socowi 我会记住这一点。然而,因为我只是以一种愚蠢的方式缩短了输入,并没有看到它由 6 行组成:)。每个块的行数是可变的。
  • 类似于为grep 生成模式,您可以为sed 生成/…/,/…/p-模式。但是,由于您已经接受了答案,因此无需 :)
【解决方案2】:

每个 OP 的要求是处理大量数据(数百万行、数 GB 数据,以及需要检索大约 100 项数据)。现代 bash 在技术上是可行的,但它不太可能表现良好。一个更好的脚本引擎在这里会做得更好。

此处介绍了可能的 bash/awk 解决方案。它将扫描每个引用的文件一次,然后一次提取所有选定的标签。请注意,“标签”列表将被扫描多次,但暗示它的大小是合理的

#! /bin/bash -uex
TAGS=data.txt

file_list=$(awk '{ print $1 }' < $TAGS | sort -u)

for f in $file_list ;
do
        gz_name=${f%/}.gz
        zcat $gz_name | awk -v F=$f '
        # Remember tags to retrieve
!DATA && $1 == F { tags[$2] = 1 }
        # OUT set to current output file, empty if item not selected
DATA && $1 == "##########" && $2 == "Name:" {
        OUT = tags[$3] ? $3 ".out" : "" ;
}
OUT { print >OUT }
' $TAGS DATA=1 -
done

不用说,可以使用 Python、Perl、Javascript 或您最喜欢的文本处理工具编写上述 5 行 awk 作业。使用样本数据集进行测试。

【讨论】:

  • 谢谢破折号。这太棒了,而且非常完美!您将为我节省大量处理时间,并希望有助于更有效地发现类似于 LSD、psilocin 或其他类似分子的新药 :)。如果您觉得有创意并想在 python(我使用 ++)或 perl(我有时使用)或其他任何东西中提出一些建议,请随意!
猜你喜欢
  • 1970-01-01
  • 2012-12-25
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
  • 1970-01-01
  • 2017-04-12
相关资源
最近更新 更多