循环遍历 awk 输出

循环遍历 awk 输出

我有一系列的字符串。它们由标记为“节点”的较小字符串组成,有时单独存在,有时通过字符:或连接,

我想将较大的字符串(“标题”)拆分为“节点”。

我已经设法用 sed 删除了一些额外的字符 ( >, ;, '),并且我使用 awk 来分割剩余的字符串:,

问题是我想循环遍历输出(“节点”),而不仅仅是第一个 awk 列。我尝试过使用{print $0}for awk,但这只是打印出带有分隔符等的初始字符串。

请帮忙?

示例输入(由示例中的 for 循环处理,在较大的代码中,它是 if/else 的输出):

>NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';
>NODE_4338305_length_1150_cov_1.0000_ID_8676609;
>NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';

示例输出(没有节点 NODE_4338305,因为它是独立的):

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

理想情况下,我想循环遍历上面的每个条目(NODE_3028138_length_2215_cov_1.9513_ID_6056275,然后NODE_6264558_length_375_cov_4.0000_ID_12529115等)

for i in ">NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';" \
">NODE_4338305_length_1150_cov_1.0000_ID_8676609;" \
">NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';"
do      
if [[ $i == *":"* ]];         
then 
echo $i            
i=$(sed "s/[>;\']//g" <<< $i);            
echo $i
echo $i | awk -F '[:,]' '{print $1}' | while IFS= read -r line; do echo "$line"; done
fi; done

编辑添加操作系统信息:

  • 操作系统:CentOS Linux 7(核心)
  • 内核:Linux 3.10.0-1127.el7.x86_64
  • 架构:x86-64

答案1

您不需要显示任何步骤。如果我理解正确的话,您将从一组 fasta 文件开始,其格式如下所示:

>header
sequence

您想要提取标头,删除>和 任何内容'并将它们拆分为,;。如果是这样,您可以直接对 fasta 文件本身执行此操作:

$ sed -n '/^>/{s/>//; s/[,:]/\n/gp}' *.fasta | tr -d "';"
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

解释

  • sed -n:抑制正常输出,除非明确告知,否则不打印任何内容。
  • /^>/{something}:如果该行以 a 开头>,则执行something
  • s/^>//;>:从行首删除。
  • s/[,:]/\n/gp:替换所有(全部因为g末尾的),:换行符( )然后打印(因为末尾\n的而打印。p
  • tr -d "';":删除任何;'

在您的评论中,您说您尝试过'i=$(sed "s/[:,]/\n/g" <<< $i)'但只得到空格,而不是换行符。那是因为你然后运行echo $i而不是echo "$i",所以换行符丢失了。


如果您确实需要对显示的字符串集合执行此操作,您可以执行以下操作:

for i in ">NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';" ">NODE_4338305_length_1150_cov_1.0000_ID_8676609;" ">NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';"; do 
    sed -n '/^>/{s/>//; s/[,:]/\n/gp}' <<<"$i" | tr -d "';" ; 
done
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

答案2

以下解决方案有些粗糙,但应该可行。正如您在示例输入中所示,假设所有节点都以字符串开头NODE(如果不是这种情况,您需要提供更完整的输入示例)。

假设您的字符串实际上位于 file 中input.txt,则以下awk调用即可解决问题:

awk '{gsub(/[:>,;\047]/,""); n=split($0,a,/NODE/); for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
  • gsub()这将首先使用(\047是单引号',不能逐字放置在命令行上,因为awk命令本身位于单引号内)替换所有“额外”字符。
  • 然后,它将剩余的字符串拆分为模式中的字段NODE,并将结果存储在数组中a
  • 然后,除第一个字段(即第一次出现 之前的字符串NODE)之外的任何“字段”都将单独打印,并NODE预先添加。

对于您的示例输入,结果是:

awk '{gsub(/[:>,;\047]/,""); n=split($0,a,/NODE/); for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_4338305_length_1150_cov_1.0000_ID_8676609
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

如果你想跳过只包含一个这样的“节点”的行,命令可以修改为:

awk '{gsub(/[:>,;\047]/,""); if ((n=split($0,a,/NODE/))<3) next; for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

答案3

尝试使用下面的 python 方法

#!/usr/bin/python
import re
m=re.compile(r'[:;,]')
k=open('filename','r')
for i in k:
    co=i.count("NODE")
    if co > 1:
        q=i.strip()
        k=re.sub(m,"\n",q)
        print k.strip().replace("'","").replace(">","")

输出

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

awk:awk 中已经提供了最好的解决方案,这只是我的尝试

awk '{print $0,gsub("NODE",$0)}' filename| awk '$NF >1 {print $1}'| sed "s/[;:,]/\n/g"|sed '/^$/d'| sed "s/[\>']//g"

答案4

使用sed编辑器我们可以生成所需的输出,如下所示。

sed \
  -e '/\n/{/^\n/!P;D;}'                    \
  -e "/^>NODE_.*NODE/ y/>;:,'/\n\n\n\n\n/" \
  -e '/\n/G;D'                             \
file

结果:

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

工作方法:

  • 只有包含至少两个节点的行加上它们以开头的行>NODE_ 让我们称它们为“有趣的”行。我们将有趣的行中每个出现的 更改>;:,'为换行符。
  • 然后在感兴趣的行中附加一个换行符,以防它不以分号结尾。该D命令将启动隐式循环并将我们带到 sed 代码的第一行。
  • 第一行是所有操作发生的地方,并且有趣的行被完全消耗,同时 sed 连续输出节点,每行一个。

相关内容