【问题标题】:Parsing a file line by line for key character in string and copying line逐行解析文件以获取字符串中的关键字符并复制行
【发布时间】:2014-03-25 05:28:30
【问题描述】:

我正在尝试解析 DNA 蛋白质文件。我只想提取一定数量的信息。我只想解析该行以“ATOM”开头并且在第四列的末尾有 G、A、T、C 之一。例如,在 DG 下面的 sn-p 中会被解析,因为它最后有一个 G。然后将该行保存在文件中。我正在使用 bash。你会用什么来做到这一点? grep、find、sed、awk 还是某种正则表达式?

感谢您的帮助!

    HETATM  103 HG22 MVA A   8       4.999  -1.260   2.090  1.00  0.00           H            
    HETATM  104 HG23 MVA A   8       5.639  -2.810   2.604  1.00  0.00          H  
    TER     105      MVA A   8                                                      
    ATOM    106  O5'  DG C  11     -12.710   1.571 -11.945  1.00  0.00           O  
    ATOM    107  C5'  DG C  11     -13.491   2.438 -11.111  1.00  0.00           C  

原问题的补充:

计算总行数和单个 G、A、T、C?将统计的总数输出为 Total Lines、TOTAL G、TOTAL T、TOTAL A、TOTAL C 的文件。

【问题讨论】:

  • 如何将代码放入 cmets 中??
  • #!/bin/bash FILENAME=$1 count=0 while read LINE do let count++ # echo "$count $LINE" VARIABLE="COMPND DNA" VARIABLEDNA="DNA" # 这是常规的表达式: if echo "$LINE" | grep -q "$VARIABLEDNA";然后在读取 LINE 时执行 if echo `expr match "$LINE" '(.[D]*[A].)' then echo 'match' done break echo "$count $LINE" fi done
  • 无论如何我都不需要处理我的代码。我需要使用 bash。我认为我的表达方式不适合寻找 DNA 链。我可以解析每一行并找到 ATOM,但是在我找到“ATOM”行之后,如何在距离行首四处的单词的末尾找到 G、C、A、T。
  • 关于超级用户的同样问题:superuser.com/q/720655/4714
  • 我在 SuperUSer 没有得到答案,由于这里有讨论,我关闭它。

标签: regex bash parsing sed awk


【解决方案1】:

希望我有机会回答它,因为 OP 质疑 Kent 的回答。这是一个问题:

If you notice Line 3 of the example the 3rd column is blank will this matter, it shouldn't in this case because its not an ATOM but if it was?

所以修复就在这里,(基于格式和位置没有改变。

awk '/^ATOM/&&substr($0,20,1)~/[GATC]/'  file

测试结果:

$ cat file
HETATM  103 HG22 MVA A   8       4.999  -1.260   2.090  1.00  0.00           H
HETATM  104 HG23 MVA A   8       5.639  -2.810   2.604  1.00  0.00           H
ATOM    105      MVA X   8
ATOM    106  O5'  DG C  11     -12.710   1.571 -11.945  1.00  0.00           O
ATOM    107  C5'  DG C  11     -13.491   2.438 -11.111  1.00  0.00           C

$ awk '/^ATOM/&&substr($0,20,1)~/[GATC]/'  file
ATOM    105      MVA X   8
ATOM    106  O5'  DG C  11     -12.710   1.571 -11.945  1.00  0.00           O
ATOM    107  C5'  DG C  11     -13.491   2.438 -11.111  1.00  0.00           C

编辑新请求。

awk '/^ATOM/&&substr($0,20,1)~/[GATC]/{print;l++;a[substr($0,20,1)]++}END{printf "total line : %s\n",l;for (i in a) printf "%s : %s \n",i,a[i]}'  file

ATOM    105      MVA A   8
ATOM    106  O5'  DG C  11     -12.710   1.571 -11.945  1.00  0.00           O
ATOM    107  C5'  DG C  11     -13.491   2.438 -11.111  1.00  0.00           C
total line : 3
A : 1
G : 2

【讨论】:

  • 这似乎是最好的解决方案。谢谢你。有没有办法计算复制的每个字母的行数?例如上面的 G 有 2 行,A 有 1 行。如果这很难,那就是一个总数。谢谢。
  • 是的,可以做到。可以在您的问题中更新您的请求,并提供您的导出输出。
  • 我更新了。一个带有计数器的循环,您可以计数,保持总数,但使用 awk,您如何利用该迭代?
  • 谢谢!哇,真的是一门语言。我可以使用 a[i] 并将其保存到数组列表或以后可以访问的东西吗?能够出于其他目的获取该信息是有用的。我在循环中使用这个命令为每个文件做同样的事情。每个文件都会有这些统计信息,因此如果将信息放入某种列表、向量或数组中,我可以稍后访问和迭代这些信息会很有用。我该怎么办?如果必须,我将在循环中的此语句之后立即完成所有工作?
  • 很高兴为您提供帮助,您需要投票或接受以表示感谢。如果您需要任何新的陈述,我建议您开始一个新的话题。
【解决方案2】:

这可能对你有用(GNU sed):

sed -nr '/^ATOM.{15}[GATC]/w newfile' oldfile

由于列可能为空,因此必须在行中的位置进行匹配。

【讨论】:

  • 我可以在 bash 中使用 sed 吗?
【解决方案3】:

这是一种老式的bash方式:

while read -ra fld; do 
  [[ ${fld[0]} == "ATOM" ]] && [[ ${fld[3]} =~ [GATC]$ ]] && echo "${fld[@]}"
done < dnafile.old > dnafile.new

【讨论】:

  • 阅读时“-ra fld”是什么意思?这就像阅读“同时阅读LINE”吗?还有 dnafile.old 和 dnafile.new 我可以将它们设置为像这样的参数“ dnafile.old= $1; dnafile.new=$2 ”吗?
  • @MAXGEN -r 代表raw input。它可以防止对反斜杠转义的解释,并且-a 将数据逐字读取到指定的数组中,在我们的例子中是fld。然后将数组的第一个元素与ATOM 进行比较,并查找以[GATC]$ 结尾的第四个元素。数组的索引是0,所以我们的第一个元素是${fld[0]}。是的,您可以将文件名分配给变量和您的变量。
  • 那么每一行是如何进入的呢?我之前还需要“while read LINE; do”吗?
  • k 我不确定 .old 和 .new 是不是,如果这只是伪代码,但我将其更改为执行命令的参数并且效果很好。我的结果目前似乎是正确的。我谢谢你。我正在使用你的答案,因为你说它是 bash。其他答案在 bash 中不兼容吗?我必须解析更大的文件集,所以我是否正在寻找非常有效的方法?如果是这种情况,我可以研究 bash 中的任何内容以提高效率吗?
  • 你也可以使用glob-style匹配:[[ "${fld[3]}" == *[GATC] ]]
【解决方案4】:

嗯...在优秀 Kent 的awk 解决方案之后,我正在犹豫是否要写一个很长的正则表达式:) :)

grep -P 'ATOM\s+\S+\s+\S+\s*\S*[GATC]\s+' dnafile

这需要一个带有 -P 的 grep - perl 正则表达式。

没有 perl 正则表达式,标准正则表达式要长得多,

grep  'ATOM  *[^ ][^ ]*  *[^ ][^ ]*  *[^ ][^ ]*  *[^ ]*[GATC]  *' dnafile

【讨论】:

  • 我可以在 bash 中使用任何一个吗?
【解决方案5】:
awk '/^ATOM/&&$4~/[GATC]$/' input > output

【讨论】:

  • 在我读完这个问题之前,我看到了一个很棒的简短答案。所以,是的,废话! :).
  • 这看起来很漂亮...我会用结果报告一点。谢谢你。你能解释一下,让我学习一下吗?我可以在 bash 中毫无问题地使用 awk 吗?
  • @Kent,这不会匹配GAPATM 等字符串吗?我只是好奇。
  • @l'L'l 我花了一些时间才发现您的用户名中的第一个字母是 1 or I or l... ;-) [ABC] 表示 single 字符, A or B or C 并把$ 放在最后,表示该字段的最后一个字符必须是G or A or T....
  • @Kent,是的,我很想看看你想出的正则表达式来弄清楚我名字的第一个字母是什么! :D 关于$,这是终止我现在可以看到的模式的好方法——感谢您的解释:)
猜你喜欢
  • 2021-08-18
  • 2020-03-20
  • 2013-12-12
  • 1970-01-01
  • 2021-02-24
  • 2019-06-28
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
相关资源
最近更新 更多