如何检查列的值位于其他文件中两列的值之间,并从Unix中的列打印相应的值?

时间:2014-07-07 10:50:53

标签: unix awk

我有两个要比较的文件。我发现如何根据条件比较列和打印。我的问题在于我必须检查file1中列[2]的值是否位于file2中的值中,该值定义为两列中的范围col [2] col [3]。如果这是真的,那么我应该在我的file1中打印文件2的列[4]。

文件1:

scaffold1_size11    12
scaffold2_size22    26
scaffold3_size33    67

file2的:

scaffold1_size11    1   10  Os01
scaffold1_size11    12  20  Os08
scaffold1_size11    29  59  Os07
scaffold2_size22    17  24  Os09
scaffold2_size22    27  38  Os09
scaffold2_size22    39  60  Os10
scaffold2_size22    67  78  Os10
scaffold3_size33    15  27  Os03
scaffold3_size33    29  62  Os08
scaffold3_size33    64  78  Os02
scaffold3_size33    80  98  Os01

期望的输出:

scaffold1_size11    12  Os08
scaffold2_size22    26
scaffold3_size33    67  Os02

应该怎么做?

2 个答案:

答案 0 :(得分:1)

这是一个执行您想要的shell脚本。它使用awk将file2转换为另一个awk脚本(tmp.awk),后者又过滤file1。

awk '{ a[$1] = a[$1] "$2 >= " $2 " && $2 <= " $3 " ? \"" $4 "\" : "; } END { for (i in a) print "$1 == \"" i "\" { print $0 \"\\t\" (" a[i] "\"\"); }"; }' file2 > tmp.awk
awk -f tmp.awk file1

注意:

  • file1中的重复行导致输出中出现重复的行。如有必要,请将结果通过uniqsort -u
  • 这种方法基于这样的假设:通常,file2相对较小(与可能较大的文件1相比);如果没有,那么这种方法可能会遭遇糟糕的表现。

答案 1 :(得分:0)

awk中的标准成语使用FNR(文件记录编号)和NR(总记录编号)来检测您何时阅读第一个文件。您在数组中读取并保存第一个文件的值,然后在读取第二个文件时使用数组。

在此上下文中,您希望首先阅读file1,根据第1列($1)中的值保存记录。这假设file1(第一个字段)中的键是唯一的。然后,在阅读第二个文件时,

awk 'FNR == NR { val[$1] = $2 }
     FNR != NR { if ($1 in val && val[$1] >= $2 && val[$1] <= $3)
                     print $1, val[$1], $4
               }' file1 file2

示例输出:

scaffold1_size11 12 Os08
scaffold2_size22 26 Os09
scaffold3_size33 67 Os02

请注意,这与问题中的示例输出不同,即:

scaffold1_size11    12  Os08
scaffold2_size22    26
scaffold3_size33    67  Os02

我认为这是问题中的拼写错误,因为file2中的所有行都没有丢失第四列。

您还会看到使用的习语如下:

awk 'FNR == NR { …save…; next }
     { …process… }'

next在读取第一个文件时跳过第二个代码块。它可能稍微有点效率,但我倾向于喜欢两个倒置条件的明确清晰度。

如果输出中的间距有问题,请使用适当的printf语句代替print