Bash - 根据另一个文件中的值选择文件行

时间:2014-01-19 21:38:55

标签: bash select

我有2个文件;让我们称它们为file1和file2。 file1包含每行中的开始和结束坐标,例如:

start end
2000 2696
3465 3688
8904 9546

file2有几列,其中第一列与问题最相关:

position v2 v3 v4
3546 value12 value13 value14
9847 value22 value23 value24
12000 value32 value33 value34

现在,我需要输出一个新文件,该文件只包含file2的行,其中'position'值(第1列)位于任何列的'start'和'end'值之间of file1。在R我只做一个双循环,但它需要太多时间(文件很大),所以需要在bash中进行。如果问题不清楚,可以使用R循环:

for(i in 1:dim(file1)[1]){
for(j in 1:dim(file2)[1]){
if(file2[j,1]>file1$start[i] & file2[j,1]<file1$end[i]) file2$select=1 else file2$select=0
}
} 

非常确定有一种简单的方法可以使用bash / awk ...

4 个答案:

答案 0 :(得分:2)

awk看起来像这样,但你需要先从file1和file2中删除第一行:

awk 'FNR==NR{x[i]=$1;y[i++]=$2;next}{for(j=0;j<i;j++){if($1>=x[j]&&$1<=y[j]){print $0}}}' file1 file2

“FNR == NR”之后的花括号中的位仅适用于file1的处理,它表示将field1存储在数组x []和field2中的数组y []中,因此我们有每个的上限和下限范围。第二组花括号中的位仅适用于处理file2。它表示迭代数组x []和y []中的所有边界,并查看field1是否在边界之间,如果是,则打印整个reocrd。

如果你不想在开始时删除标题行,你可以使awk更复杂一点,并忽略它:

awk 'FNR==1{next}FNR==NR{x[i]=$1;y[i++]=$2;next}{for(j=0;j<i;j++){if($1>=x[j]&&$1<=y[j]){print $0}}}' file1 file2

<强> EDITED

好的,我添加了代码来检查“染色体”(无论是什么!),假设它位于两个文件的第一个字段中,如下所示:

File1中

x 2000 2696
x 3465 3688
x 8904 9546

文件2

x 3546 value12 value13 value14
y 3467 value12 value13 value14
x 9847 value22 value23 value24
x 12000 value32 value33 value34

因此,代码现在也将染色体存储在数组c []中,并在输出之前检查它们是否相等。

awk 'BEGIN{i=0}FNR==NR{c[i]=$1;x[i]=$2;y[i++]=$3;next}{for(j=0;j<i;j++){if(c[j]==$1&&$2>=x[j]&&$2<=y[j]){print $0;next}}}' file1 file2

答案 1 :(得分:0)

不知道如何在bash中执行此操作...

我会尝试一个perl脚本,读取第一个文件并将其存储在内存中(如果可能,它取决于它的大小)然后逐行浏览第二个文件并进行比较以输出行或不

我认为你也可以在R中做到这一点......同样的方法:存储第一个文件,循环第二个文件的每一行。

此外,如果间隔不重叠,您可以对文件进行排序以加快算法速度。

答案 2 :(得分:0)

这应该比for循环

更快
res <- apply(file2, 1, function(row)
            {
            any(row$position > file1$start & row$position < file1$end)
            })

答案 3 :(得分:0)

假设文件的分隔符是空格(如果不是 - 更改-d estting)。

该脚本使用cut来提取file2的第一个字段。 然后一个简单的grep搜索file1中的字段。如果存在,则打印file2中的行。

#!/bin/bash
while read line
do
    word=$(echo $line | cut -f1 -d" ")
    grep -c $word file1 >/dev/null
    if [ $? -eq 0 ];then
       echo "$line"
    fi
done < file2