我正在尝试从两个文件中提取数字范围。
$cat file1.txt
chr1 69509
chr1 69511
chr1 71000
chr1 358112
chr1 586874
chr1 744200
。 。 。
$cat file2.txt
chr1 69091 70005
chr1 358070 358183
chr1 586842 586955
chr1 744195 744343
。 。 。
期望的输出:
69509 CHR1 69091 70005
69511 CHR1 69091 70005
71000超出范围
358112 CHR1 358070 358183
586874 CHR1 586842 586955
744200
下面是我的 awk 代码。
awk 'NR==FNR{x[$1] = $2; next;}{for (i in x) {if (x[i] > $2 && x[i] < $3)print x[i], $1,$2,$3;else{print x[i], "out of range"}}}' file1.txt file2.txt
但是,此代码返回的输出仅包含最后一个 NR 的数据。
例如,
744200 超出范围
744200 超出范围
744200 超出范围
744200 chr1 744195 744343
我猜这与 NR 和 FNR 有关,但我不知道该怎么做。
答案1
x
这是因为您正在键入第一个文件中所有行都$1
相同的数组。chr1
因此,在每一行上,数组内容都基于相同的键进行索引,并用 中的值覆盖$2
。因此,到文件末尾时,数组中就有一个条目x['chr1']=744200
您需要唯一地存储该行。将密钥存储为元组$1 FS $2
并将逻辑修改为
awk 'NR == FNR { x[$1 FS $2] = $2; next }{
for (key in x) {
split(key, arr)
if (arr[2] > $2 && arr[2] < $3)
print arr[2], $0
else {
print arr[2], "out of range"
}
}
}' file1 file2
要改进逻辑以仅对两个文件的第一列相同的行进行范围检查,请向if
as添加一个条件
if ( (arr[2] > $2 && arr[2] < $3) && ( $1 == arr[1] ) )
答案2
假设 file2 范围不重叠,如您的示例所示:
$ cat tst.awk
NF==3 { beg=$2; end=$3; all=$0; next }
{ print $2, ( ($2 >= beg) && ($2 <= end) ? all : "out of range" ) }
$ sort -sk2n file2 file1 | awk -f tst.awk
69509 chr1 69091 70005
69511 chr1 69091 70005
71000 out of range
358112 chr1 358070 358183
586874 chr1 586842 586955
744200 chr1 744195 744343
它使用 GNU 排序(“稳定排序”)来确保在相同 s 的情况下-s
file2 条目在该条目之前打印。file1
$2