文件1:
chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 chr1 14969 15038 NR_024540_1_r_WASH7P_69 chr1 15795 15947 NR_024540_2_r_WASH7P_152 chr1 16606 16765 NR_024540_3_r_WASH7P_15 chr1 16857 17055 NR_024540_4_r_WASH7P_198
和file2:
NR_024540 11
我需要在file1
find匹配file2
并打印整个file1 + second column of file2
所以ouptut是:
chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11 chr1 14969 15038 NR_024540_1_r_WASH7P_69 11 chr1 15795 15947 NR_024540_2_r_WASH7P_152 11 chr1 16606 16765 NR_024540_3_r_WASH7P_15 11 chr1 16857 17055 NR_024540_4_r_WASH7P_198 11
我的解决scheme在bash中非常慢:
#!/bin/bash while read line; do c=$(echo $line | awk '{print $1}') d=$(echo $line | awk '{print $2}') grep $c file1 | awk -v line="$d" -v OFS="\t" '{print $1,$2,$3,$4"_"line}' >> output done < file2
我更喜欢更快的任何bash或awk解决scheme。 输出可以被修改,但需要保留所有的信息(列的顺序可以不同)。
编辑:
现在它看起来像根据@chepner最快的解决scheme:
#!/bin/bash while read -rcd; do grep $c file1 | awk -v line="$d" -v OFS="\t" '{print $1,$2,$3,$4"_"line}' done < file2 > output
另一个解决方法是使用join
和sed
,假设file1
和file2
是排序的
join <(sed -r 's/[^ _]+_[^_]+/& &/' file1) file2 -1 4 -2 1 -o "1.1 1.2 1.3 1.5 2.2" > output
如果输出顺序不重要,可以使用awk
awk 'FNR==NR{d[$1]=$2; next} {split($4,v,"_"); key=v[1]"_"v[2]; if(key in d) print $0, d[key]} ' file2 file1
你得到,
chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11 chr1 14969 15038 NR_024540_1_r_WASH7P_69 11 chr1 15795 15947 NR_024540_2_r_WASH7P_152 11 chr1 16606 16765 NR_024540_3_r_WASH7P_15 11 chr1 16857 17055 NR_024540_4_r_WASH7P_198 11
在一个Awk
命令中,
awk 'FNR==NR{map[$1]=$2; next}{ for (i in map) if($0 ~ i){$(NF+1)=map[i]; print; next}}' file2 file1 chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11 chr1 14969 15038 NR_024540_1_r_WASH7P_69 11 chr1 15795 15947 NR_024540_2_r_WASH7P_152 11 chr1 16606 16765 NR_024540_3_r_WASH7P_15 11 chr1 16857 17055 NR_024540_4_r_WASH7P_198 11
多线程中更可读的版本
FNR==NR { # map the values from 'file2' into the hash-map 'map' map[$1]=$2 next } # On 'file1' do { # Iterate through the array map for (i in map){ # If there is a direct regex match on the line with the # element from the hash-map, print it and append the # hash-mapped value at last if($0 ~ i){ $(NF+1)=map[i] print next } } }
尝试这个 –
cat file2 NR_024540 11 NR_024541 12 cat file11 chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 chr1 14361 14829 NR_024542_0_r_DDX11L1,WASH7P_468 chr1 14969 15038 NR_024540_1_r_WASH7P_69 chr1 15795 15947 NR_024540_2_r_WASH7P_152 chr1 16606 16765 NR_024540_3_r_WASH7P_15 chr1 16857 17055 NR_024540_4_r_WASH7P_198 chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 chr1 14969 15038 NR_024540_1_r_WASH7P_69 chr1 15795 15947 NR_024540_2_r_WASH7P_152 chr1 16606 16765 NR_024540_3_r_WASH7P_15 awk 'NR==FNR{a[$1]=$2;next} substr($4,1,9) in a {print $0,a[substr($4,1,9)]}' file2 file11 chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11 chr1 14969 15038 NR_024540_1_r_WASH7P_69 11 chr1 15795 15947 NR_024540_2_r_WASH7P_152 11 chr1 16606 16765 NR_024540_3_r_WASH7P_15 11 chr1 16857 17055 NR_024540_4_r_WASH7P_198 11 chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11 chr1 14969 15038 NR_024540_1_r_WASH7P_69 11 chr1 15795 15947 NR_024540_2_r_WASH7P_152 11 chr1 16606 16765 NR_024540_3_r_WASH7P_15 11
性能 – (测试55000条记录)
time awk 'NR==FNR{a[$1]=$2;next} substr($4,1,9) in a {print $0,a[substr($4,1,9)]}' file2 file1 > output1 real 0m0.16s user 0m0.14s sys 0m0.01s
您不必要地启动了大量的外部程序。 让read
从文件2拆分入线,而不是两次调用awk
。 也没有必要运行grep
; awk
可以做自己的过滤。
while read -rcd; do awk -v field="$c" -v line="$d" -v OFS='\t' '$0 ~ field {print $1,$2,$3,$4"_"line}' file1 done < file2 > output
如果搜索到的字符串总是相同的长度( length("NR_024540")==9
):
awk 'NR==FNR{a[$1]=$2;next} (i=substr($4,1,9)) && (i in a){print $0, a[i]}' file2 file1
解释:
NR==FNR { # process file2 a[$1]=$2 # hash record using $1 as the key next # skip to next record } (i=substr($4,1,9)) && (i in a) { # read the first 9 bytes of $4 to i and search in a print $0, a[i] # output if found }
awk -F '[[:blank:]_]+' ' FNR==NR { a[$2]=$3 ;next } { if ( $5 in a ) $0 = $0 " " a[$5] } 7 ' file2 file1
评论:
_
作为额外的字段分隔符,所以文件名比较容易在两个文件中进行比较(只使用数字部分)。 一个较小的oneliner代码(针对代码大小进行了优化)(假定file1中的非空行是必需的)。 如果分隔符只有空格,则可以用空格字符替换[:blank:]
awk -F '[[:blank:]_]+' 'NF==3{a[$2]=$3;next}$0=$0" "a[$5]' file2 file1
没有awk
或sed
需要。 这假定file2只有一行:
n="`cut -f 2 file2`" ; while read x ; do echo "$x $n" ; done < file1