在bash或sed中逐行计算匹配前后的字符串长度

时间:2016-06-23 17:02:56

标签: string bash awk sed

我有一个DNA序列的'测试'文件,每个都有一个标题或ID,如下所示:

>new
ATCGGC
>two
ACGGCTGGG
>tre
ACAACGGTAGCTACTATACGGTCGTATTTTTT

我想在匹配之前和之后打印每个连续字符串的长度给定字符串,例如CGG

输出将如下所示:

>new
2 1
>two
1 5
>tre 
4 11 11 

或者可以只有每行匹配前后的字符长度。

2 1
1 5 
4 11 11 

我第一次尝试使用sed在找到'>'后打印下一行,然后找到每个grep匹配“CGG”的字节偏移量,我将用它来转换为长度,但这产生了以下结果:

sed -n '/>/ {n;p}' test | grep -aob "CGG" 

2:CGG
8:CGG
21:CGG
35:CGG

基本上,grep为每个匹配打印字节偏移,向上计数,而我希望每行独立的字节偏移(即在每行之后重置)。

我想我也需要使用sed进行搜索,因为它逐行操作,但我不知道如何抵消给定字符串中的字节偏移或字符。

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:7)

通过使用给定的字符串作为awk中的字段分隔符,可以轻松地遍历每行上的字段并打印它们的长度。 (以>开头的行我们只是按原样打印。)

这为您的示例数据提供了所需的输出,但您可能希望检查边缘情况,例如以CGG开头,以CGG结尾,仅包含CGG等。

$ awk -F CGG '/^>/ {print; next} {for (i=1; i<=NF; ++i) {printf "%s%s", length($i), (i==NF)?"\n":" "}}' file.txt
>new
2 1
>two
1 5
>tre
4 11 11
  

awk -F CGG

使用“CGG”作为字段分隔符调用awk。这会将每一行解析为一组字段,这些字段由字符串“CGG”的每个(如果有)出现。 “CGG”字符串本身既不包含在任何字段中,也不包含在任何字段中。

因此,行ACAACGGTAGCTACTATACGGTCGTATTTTTT被解析为三个字段:ACAATAGCTACTATATCGTATTTTTT,由$1表示在awk程序中,{分别为{1}}和$2

  

'/ ^&gt; / {print;下一个}

此模式/操作告诉awk如果行以$3开头打印行并立即转到下一行输入,而不考虑awk程序中的任何进一步模式或操作。

  

{for(i = 1; i&lt; = NF; ++ i){printf“%s%s”,length($ i),(i == NF)?“\ n”:“”}}

如果我们到达此操作,我们知道该行>开头(见上文)。由于只有一个动作而没有模式,因此对于到达此处的每一行输入执行动作。

for循环遍历所有字段(>是一个特殊的awk变量,包含当前行中的字段数)并打印它们的长度。通过检查我们是否到达最后一个字段,我们知道是打印换行还是仅打印空格。