awk NR == FNR用于命令语法

时间:2018-12-17 21:18:38

标签: bash awk fastq

我无法使用awk NR==FNR从输入的.fastq文件返回感兴趣的行。

我有以下示例输入文件,名为example.fastq

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.2 2/1
CTATANTATTCTATATTTATTCTAGATAAAAGCATTCTATATTTAGCATATGTCTAGCAAAAAAAA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

我正在尝试提取包含感兴趣的字符串的四行的组,重要的是必须允许近似匹配,因此使用agrep代替grep。下面的示例有效。

agrep -1 -n "GAAATAATA" example.fastq | awk -F: 'NR==FNR{for(i=($1-1);i<=($1+2);i++)a[i];next}FNR in a' - example.fastq

上面的命令产生以下正确的输出。

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

但是,如果我使用第二行中未包含的序列,则此命令仍将打印前两行,如以下示例所示。

agrep -1 -n "TAGATAAAACT" example.fastq | awk -F: 'NR==FNR{for(i=($1-1);i<=($1+2);i++)a[i];next}FNR in a' - example.fastq

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

感谢您帮助我了解此awk命令的行为。

3 个答案:

答案 0 :(得分:1)

您的输入中没有冒号(:),因此$1代表整行,($1-1)($2+2)将成为-12,这意味着您的for循环将始终精确运行四次(对于i等于-101的值,然后是2)。

for循环中,您确保存在a[i](即a[-1]a[0]a[1]a[2]

您的代码的最后一部分将打印当时正在检查的行(但由于前一个节中的next而不会从第一个文件打印),只要数组a包含该行的条目文件的行号。因此,它从每个输入中打印第1行和第2行(因为a[FNR]等于1或2的情况下存在FNR

由于您需要一个近似的答案,因此必须使用agrepJames Brown's answer to your other question提出的想法很有意义,但其实现(如上文所述)没有意义。

以下解决方案使用agrep的匹配作为围绕匹配行打印的提示(agrep不支持grep的{​​{1}}和-A NUM,否则我们可以-B num来获得更简单的答案)。

agrep -A1 -B2 -1 -n PATTERN example.fastq

这将两次检查输入文件。第一次使用agrep -1 "GAAATAATA" example.fastq | awk ' NR == FNR { agrep_hit[$0] = 1; next } agrep_hit[$0] { print last_line; i = 1 } 0 < i && i < 4 { i++; print } { last_line = $0 } ' - example.fastq 查找近似模式匹配,而第二次使用agrep获取请求的上下文行。

awkawk)中的总行号等于本地文件的行号(NR)时,这意味着我们正在检查第一个输入(FNR ,即标准输入,即-的输出)。我们将近似模式命中存储在关联数组中以备后用,然后使用agrep移至下一行(因此,其余next命令仅在以后的输入中起作用)。

由于您需要上一行,因此我们必须显式打印它。 awk代码的最后一个节将当前行另存为awk,以便我们稍后进行检索。在last_line输出的行(并因此存储在数组中)上,我们打印保存的agrep并将迭代器last_line设置为i

1i12时,我们将其递增并打印当前行。这将打印出匹配的行,然后再打印出两行以显示上下文。

答案 1 :(得分:1)

您可以使用以下agrep + awk解决方案:

srch() {
   awk -F ': ' 'NR==FNR {
      a[$1] = 1
      next
   }
   a[FNR] {
      print p
      print
      for (i=0; i<2 && getline > 0; i++)
         print
   }
   {
      p=$0
   }' <(agrep -1 -n "$2" "$1") "$1"
}

然后以以下方式运行它:

srch file 'GAAATAATA'

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

这:

srch file 'TAGATAAAACT

@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6'

答案 2 :(得分:0)

具有记录分隔符定义(GNU awk

$ awk -v RS='(^|\n)@' '/GAAATAATA/{printf "%s", rt $0} {rt=RT}' file

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6