对制表符分隔文件中的嵌套列进行算术运算

对制表符分隔文件中的嵌套列进行算术运算

我有一个制表符分隔的文本文件,其中包含Column1...Columnn列和R1Rn。在某些列中,有多个嵌套字段,它们带有标识符,然后用分号分隔(在附加的示例图像文件中以红色显示)。确切地说,我附上了该文件的示例快照。

在此处输入图片描述

这里Column6中的数据INFO有多个嵌套字段如DP; RPB; AF1; AC1; DP4;...等。

任务:inputfile.txtColumn6 中INFO选择字段DP4=a,b,c,d并需要对DP4=a,b,c,d值执行简单的算术运算(在图像中标记为红色),例如(c+d)/(a+b+c+d)-> 并将每行的结果粘贴为INFOextra同一文件中的新列。

如何在 e unix shell 脚本中完成此操作?

答案1

awk '$1=="ID" {print $0 "\tINFOextra"; next}; NF { info=$6; gsub(/.*;DP4=|;MQ=.*/, "", info); split(info, a, /,/); print $0 "\t" (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4])}' inputfile.txt > outputfile.txt
# then check the content outputfile.txt and rename it if important

如您所见,解决方案与您上一个问题的答案非常相似,而且一点也不长。这是因为 awk 经过了极其精细的调整,可以解决像您这样的问题。我建议您查看其手册页(http://linux.die.net/man/1/awk) 来了解它与其他(更通用的)语言相比有多么简单。

如果要将多个输入文件处理为具有适当名称的多个输出文件,则选项如下:

  • 在 shell 中创建一个循环并逐个启动每个文件的一个 awk 进程
  • 让 awk 将输出写入文件,这些文件的名称取决于当前输入文件的名称,这些信息存储在 awk 的 FILENAME 变量中,该变量在处理过程中自动设置。在 awk 代码中,可以使用与 shell 相同的语法和类似的结果来重定向:

    awk '$1=="ID" {print $0 "\tINFOextra" > FILENAME ".out"; next}; NF { info=$6; gsub(/.*;DP4=|;MQ=.*/, "", info); split(info, a, /,/); 打印 $0 "\t" (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4]) > FILENAME ".out"}' 输入文件 1.txt 输入文件 2.txt

这里,每个 inputfileN.txt 实例都会有一个对应的 inputfileN.txt.out 文件。FILENAME 是一个简单的字符串,因此对输出文件的任何操作都是有效的。

当规范变得复杂,以至于附加字段必须出现在内部位置(而不是开头或结尾)时,应考虑创建一个子例程(在 awk 中称为函数)来创建输出行。此处的函数遍历所有字段,并照常打印它们,但在附加字段应该出现的位置,它会将其写入第 n-1 个字段之后和第 n 个字段之前,使其成为第 n 个字段。现在,值得将 awk 代码放在其自己的文件中:

$ cat bio.awk


function myprint( str) {
   for (i=1; i<=NF; ++i) {
      printf "%s", $i  > FILENAME ".out"
      if (i==44)
         printf "\t%s", str  >> FILENAME ".out"
      if (i!=NF)
         printf "\t"  >> FILENAME ".out"
   }
   print ""  >> FILENAME ".out"
}

$1=="ID" {
   myprint( "INFOextra")
   next
}

NF {
   info=$6
   gsub(/.*;DP4=|;MQ=.*/, "", info)
   split(info, a, /,/)
   myprint( (a[3]+a[4])/(a[1]+a[2]+a[3]+a[4]) )
}

然后调用它会产生一个更短更干净的命令行:

awk -f bio.awk inputfile1.txt inputfile2.txt

相关内容