使用其他文件最有效地搜索大型制表符分隔文件

时间:2017-06-26 13:19:29

标签: awk sed grep

我正在尝试找到一个更快(最有效)的工具来搜索非常大的~100GB file2。搜索的输入是file1,它只是列中#'s的列表(每行1个)---可能有几百---。 File2是特定格式的ID的排序列表,其中#file1$2中的file2值匹配。我尝试了各种grepawkack命令,但它们似乎都有用,但也许有更好的方法。下面的命令似乎有点帮助但是因为可能有很多#s来查找它可能不是最好的方法。谢谢 :)。下面的每一个都在大约40分钟内完成,而file1只有2行,它通常有100行。谢谢:)。

<file2 sed -e 's/^/(^|,)/' -e 's/$/($|,)/' | grep -E -f - file1 > out

awk

BEGIN { FS=OFS="\t" }
NR==FNR {
c = ++num[$1]
beg[$1][c] = $1
val[$1][c] = $NF
next
 }
$2 in val {
for (c=1; c<=num[$1]; c++) {
if ( (beg[$1][c] = $2) ) {
    print $0, val[$1][c]
    break
  }
 }
}

文件1

2307492
7349185

file2 tab-delimited

NC_000001.10:g.26131654G>A  7349185
NC_000001.11:g.25805163G>A  7349185
XM_006715659.1:c.1454-13758T>C  22
XM_006715660.1:c.1454-13758T>C  22    
XR_921761.2:n.662T>C    2307492
XR_922278.2:n.1307-31218A>G 2307492

所需的输出

NC_000001.10:g.26131654G>A  7349185
NC_000001.11:g.25805163G>A  7349185 
XR_921761.2:n.662T>C    2307492
XR_922278.2:n.1307-31218A>G 2307492

3 个答案:

答案 0 :(得分:2)

如果您想确保file1中的数字专门位于file2的最后一列,您可以将sed与生成的命令文件一起使用:

首先使用sedawk生成命令文件:

$ awk '{printf "/\t%s$/p\n", $1}' file1
/   2307492$/p
/   7349185$/p

然后将其提供给sed以处理文件2:

$ sed -n -f <(awk '{printf "/\t%s$/p\n", $1}' file1) file2
NC_000001.10:g.26131654G>A  7349185
NC_000001.11:g.25805163G>A  7349185
XR_921761.2:n.662T>C    2307492
XR_922278.2:n.1307-31218A>G 2307492

如果只打印file1file2中的某个数字,则可以使用grep

$ grep -wFf file1 file2
NC_000001.10:g.26131654G>A  7349185
NC_000001.11:g.25805163G>A  7349185
XR_921761.2:n.662T>C    2307492
XR_922278.2:n.1307-31218A>G 2307492

或者,使用awk,您可能会读取文件1中的数字,拆分为\t并测试文件2的第2列:

$ awk -F"\t" 'FNR==NR{fi[$1]; next}
              $2 in fi' file1 file2
NC_000001.10:g.26131654G>A  7349185
NC_000001.11:g.25805163G>A  7349185
XR_921761.2:n.662T>C    2307492
XR_922278.2:n.1307-31218A>G 2307492

任何这些(我认为)都会像你没有数据库那样快。

答案 1 :(得分:1)

不确定它是否会比你尝试的更快,但我想到的是:

在正则表达式中转换file1以传递给awk,并在解析file2的每一行时应用正则表达式:

awk -F"\t" -v regex=`awk '{printf "%s|",$0} END{printf "\b"}' file1` '$2~regex{print $0}' file2

详细信息:

awk '{printf "%s|",$0} END{printf "\b"}'将转换:

2307492
7349185

收件人:2307492|7349185

由于之前的正则表达式存储在regex变量中:

'$2~regex{print $0}'表示:'$2~/2307492|7349185/{print $0}'即:如果$2与正则表达式匹配,则打印该行

答案 2 :(得分:1)

尝试:

awk 'FNR==NR{a[$0];next}($NF in a)' file1 file2

所以在这里检查一个条件FNR == NR当第一个文件被读取时它将为TRUE(在这种情况下为file1)。然后创建名为a的数组,其索引为$ 0(仅在file1中为当前行),使用next将停止游标进一步运行,以便不再执行所有其他命令。 现在提到条件检查是否$ NF(file2的最后一个字段)存在于数组a中,如果是,则打印file2的当前行(awk工作条件然后是action方法,因此如果条件为TRUE则应该发生某些操作,因此在此case没有提到动作所以默认情况下会发生打印当前行的文件2)。