awk NR==FNR 命令语法

awk NR==FNR for command syntax

我在使用输入 .fastq 文件中的 awk NR==FNR 至 return 行时遇到问题。

我有以下名为 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);i<=(+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);i<=(+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 命令的行为。

您的输入中没有冒号 (:),因此 </code> 指的是整行,而 <code>(-1) & (+2) 将是 -12,这意味着您的 for 循环将始终 运行 恰好四次(对于 i 等于 -10 的值, 1, 然后 2).

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

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

由于您需要一个大概的答案,因此必须使用 agrep 提出的想法是有道理的,但它的实现(如上文所述)没有意义。

以下解决方案使用 agrep 的命中作为提示,让周围的行与命中一起打印(agrep 不支持上下文行,如 grep-A NUM-B num 否则我们可以做 agrep -A1 -B2 -1 -n PATTERN example.fastq 以获得更简单的答案)。

agrep -1 "GAAATAATA" example.fastq | awk '
  NR == FNR { agrep_hit[[=10=]] = 1; next }
  agrep_hit[[=10=]] { print last_line; i = 1 }       
  0 < i && i < 4 { i++; print } 
  { last_line = [=10=] }
' - example.fastq

这将检查输入文件两次。第一次使用 agrep 查找近似模式匹配,而第二次使用 awk 获取请求的上下文行。

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

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

i123 时,我们将其递增并打印当前行。这将打印匹配行,然后再打印两行作为上下文。

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

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

然后 运行 为:

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'

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

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

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