使用awk或bash来解析行

时间:2014-11-09 23:38:23

标签: awk

我有一个包含以下类型行的文件:

 M00677:223:000000000-AB9BD:1:1101:2086:16648    163     AY243312        66733   0       95M22S  =       66733   108     ACATCATACCGATAGGAATACAAGACACTTTGCCGGCGGTTGTAGATTTATCATATTTTTTCCCTACACATTCGTTACCATTTGTTTAAAATTTATATAACACTATATTTTTCTCTT      BBBBBFFFFFBBGGEGGGGGGGHHHHHHHHHHHHGGGGGA00155555D5@55555DDGG@33333132334443B113B4BF4BC24BFH43B44B44443333444444B3??4B   NM:i:6  MD:Z:60C1A5T2C6A7A8     AS:i:65 XS:i:65    XA:Z:AY313847,+69566,95M22S,6;AY678276,+69234,95M22S,7;M35027,+69864,95M22S,7;
 M00677:223:000000000-AB9BD:1:1101:3187:21406    99      AY313847        80978   0       68M43S  =       80978   36      TTATTCCATCTGTGGAAAATAATACTCTGACATTATCGCTAATTGACACATCGGTGAGTGATCTGCCTCTACCTTCCTCCTCTTCTTTTTTCCCATATACCCGTGTACCCG    BBBABFFFFFFFAFFGGGGGGGFHHGFGFFHHCFAFFGFFGGHHHGHHGBHGEDEEFHHHHHHGHFHHHGHHHHHHHHHHHHHHHHHHFFEGHHHHBGHHHHGGGHHHHFG NM:i:2  MD:Z:0C61A5     AS:i:62 XS:i:61 XA:Z:AY678276,+80652,68M43S,2;M35027,+81282,68M43S,2;AY243312,+78151,68M43S,2;

我要过滤并且只得到AS:i:tag后面的数字大于XS:i:tag后面的数字的行。因此,在这种情况下,只应打印第二行。

我曾尝试用bash编写一个复杂的脚本,但转换成数组,然后解析ifs不起作用,听起来太复杂了。

我能用awk做这个吗?

谢谢, 阿德里安

7 个答案:

答案 0 :(得分:2)

假设:

  • 字段顺序不会更改
  • 每一行都有AS:i:XS:i:XA:Z:的小组
  • 这些字段分隔符不会在任何行中重复

然后以下内容适用于我:

awk -F"AS:i:|XS:i:|XA:Z:" '$2 > $3' data

设置字段分隔符值,然后测试每一行的值。

答案 1 :(得分:1)

我对您的数据做了一些假设,主要是AS标记始终为字段14,XS标记始终为字段15(空格分隔)。如果是这种情况并且我理解你的问题,那应该这样做:

awk '{ split($14, as_parts, ":"); split($15, xs_parts, ":"); if (as_parts[3] > xs_parts[3]) print; }' file.txt

答案 2 :(得分:1)

这很健壮

#!/usr/bin/awk -f
{
  split($0, foo)
  for (bar in foo) {
    split(foo[bar], baz, ":")
    if (baz[1] == "AS") asi = baz[3]
    if (baz[1] == "XS") xsi = baz[3]
  }
  if (asi > xsi) print
}

答案 3 :(得分:0)

如何使用Python和正则表达式?也许还有什么东西?

import re

regex1 = r"AS:i:(?P<as_val>\d*)"
regex2 = r"XS:i:(?P<xs_val>\d*)"

m = re.search(regex1, string1)
if m and m.group('as_val') is not None:
   asVal = float(m.group('as_val'))

m = re.search(regex2, string1)
if m and m.group('as_val') is not None:
   xsVal = float(m.group('xs_val'))

if asVal > xsVal ...

这不是我的头脑,但它应该非常接近你所需要的。

答案 4 :(得分:0)

中的

$ perl -lne '/AS:i:(\d+)\s*XS:i:(\d+)/; print if $2 < $1' file.txt

答案 5 :(得分:0)

假设AS:i:始终位于每行XS:i:之前,这是我能想到的最短awk 1-liner:

awk -F"[AX]S:i:" '$2 > $3' infile

输出

$ awk -F"[AX]S:i:" '$2 > $3' gattaca
M00677:223:000000000-AB9BD:1:1101:3187:21406    99      AY313847        80978   0       68M43S  =       80978   36      TTATTCCATCTGTGGAAAATAATACTCTGACATTATCGCTAATTGACACATCGGTGAGTGATCTGCCTCTACCTTCCTCCTCTTCTTTTTTCCCATATACCCGTGTACCCG    BBBABFFFFFFFAFFGGGGGGGFHHGFGFFHHCFAFFGFFGGHHHGHHGBHGEDEEFHHHHHHGHFHHHGHHHHHHHHHHHHHHHHHHFFEGHHHHBGHHHHGGGHHHHFG NM:i:2  MD:Z:0C61A5     AS:i:62 XS:i:61 XA:Z:AY678276,+80652,68M43S,2;M35027,+81282,68M43S,2;AY243312,+78151,68M43S,2;

答案 6 :(得分:0)

看起来这就是你所需要的:

awk -F'[: \t]+' '$27 > $30' file

或更灵活地使用GNU awk和gensub():

awk 'gensub(/.*\sAS:i:([0-9]+).*/,"\\1","") > gensub(/.*\sXS:i:([0-9]+).*/,"\\1","")' file