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

LP_*_*640 1 string bash awk sed

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

>new
ATCGGC
>two
ACGGCTGGG
>tre
ACAACGGTAGCTACTATACGGTCGTATTTTTT
Run Code Online (Sandbox Code Playgroud)

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

输出将如下所示:

>new
2 1
>two
1 5
>tre 
4 11 11 
Run Code Online (Sandbox Code Playgroud)

或者只能在每行的匹配之前和之后具有字符长度.

2 1
1 5 
4 11 11 
Run Code Online (Sandbox Code Playgroud)

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

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

2:CGG
8:CGG
21:CGG
35:CGG
Run Code Online (Sandbox Code Playgroud)

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

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

任何帮助将非常感激.

jas*_*jas 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
Run Code Online (Sandbox Code Playgroud)

awk -F CGG

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

因此,该线ACAACGGTAGCTACTATACGGTCGTATTTTTT被解析成三个字段:ACAA,TAGCTACTATA,和TCGTATTTTTT,通过在AWK程序表示$1,$2$3分别.

'/ ^>/{print; 下一个}

这个模式/动作告诉awk如果行开始>打印行并立即进入下一行输入,而不考虑awk程序中的任何进一步的模式或动作.

{for(i = 1; i <= NF; ++ i){printf"%s%s",length($ i),(i == NF)?"\n":""}}

如果我们到达这个动作,我们知道行并没有下手>(见上文).由于只有一个动作而没有模式,因此对于到达此处的每一行输入执行动作.

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