awk
的良好用法对我来说还不清楚,但是我知道它将对我想要的东西有用。
我有两个文件,两个文件都用制表符分隔:
transcriptome.txt
(十亿行):
>TRINITY_DN261_c0_g1_i1 GATATTTATCCGAATATTCAATATGAT
>TRINITY_DN299_c0_g1_i1 GGACACGGGCCTCAAGCCAAGTCAAAACCACCACAAAG
>TRINITY_DN216_c0_g1_i1 GTTCAATATTCAATGACTGAAGGGCCCGCTGATTTTCCCCTATAAA
>TRINITY_DN220_c0_g1_i1 GGGAGATAATAACAATGATAACACACAAAATTCCAATG
selected_genes.txt
(数千行):
>TRINITY_DN261_c0_g1_i1 1
>TRINITY_DN220_c0_g1_i1 0
我想要此输出(selected_genes.txt
的第一列和transcriptome.txt
的第二列):
>TRINITY_DN261_c0_g1_i1 GATATTTATCCGAATATTCAATATGAT
>TRINITY_DN220_c0_g1_i1 GGGAGATAATAACAATGATAACACACAAAATTCCAATG
通常,我在Excel中使用vlookup
函数。
我尝试使用awk
来获得结果,就像在许多线程(stackexchange1,stackexchange2,stackoverflow1,stackoverflow2,stackoverflow3等中一样..)
因此,我尝试使用这些线程中的建议,但是我的输出要么为空,要么仅为我的selected_genes.txt
文件的副本。
我检查了一下,我的2个文件都位于UTF-8
中,并带有CRLF
。还有,
awk '{print $1}' `transcriptome.txt`
awk '{print $1}' `selected_genes.txt`
请把文件的第一栏给我,所以问题不是出在他们身上。
这是我尝试过的:
awk -F, 'FNR==NR {a[$1]=$1; next}; $1 in a {print a[$2]}' selected_genes.txt transcriptome.txt > output.txt
# Blank result
awk -F 'FNR==NR{var[$1]=$1;next;}{print var[$1]FS$2}' selected_genes.txt transcriptome.txt > output.txt
# Blank result
awk 'NR == FNR{a[$1] = $2;next}; {print $1, $1 in a?a[$1]: "NA"}' selected_genes.txt transcriptome.txt > output.txt
# Print only transcriptome.txt with first column and NAs
awk -F, 'FNR==NR{var[$1]=$1}FNR!=NR{print(var[$2]","$1)}' selected_genes.txt transcriptome.txt > output.txt
# Print only selected_genes.txt
我没有产生想要的输出。 任何解释我的代码问题的建议将不胜感激。
答案 0 :(得分:2)
经典之作。将数千行基因文件散列为散列(a
),以免浪费数十亿行转录组文件中的所有内存和查找$1
:
$ awk '
# { sub(/\r$/,"") } # uncomment to remove Windows style line-endings.
NR==FNR{a[$1] # hash $1 of genes file to a
next
}
($1 in a) { # lookup from transcriptome
print
}' genes transcriptome # mind the order
>TRINITY_DN261_c0_g1_i1 GATATTTATCCGAATATTCAATATGAT
>TRINITY_DN220_c0_g1_i1 GGGAGATAATAACAATGATAACACACAAAATTCCAATG
答案 1 :(得分:0)
在框中,有一种比awk
更好的工具,可以在公共字段上进行这种文件合并,尤其是对于大文件:join(1)
$ join -t $'\t' -11 -21 -o 0,2.2 \
<(sort -t $'\t' -k1,1 selected_genes.txt) \
<(sort -t $'\t' -k1,1 transcriptome.txt)
>TRINITY_DN220_c0_g1_i1 GGGAGATAATAACAATGATAACACACAAAATTCCAATG
>TRINITY_DN261_c0_g1_i1 GATATTTATCCGAATATTCAATATGAT
唯一的警告是要连接的文件必须在连接列上排序,因此使用sort
。
就数据库而言,它对两个文件执行INNER JOIN
-对于第一个文件的每一行,第二个文件的每一行具有匹配的连接列,将产生一行输出。 -o 0,2.2
使这些行成为第二个文件的连接列和第二列。
另一个有趣的选择:
$ grep -F -f <(sed -e 's/[^\t]*$//' selected_genes.txt) transcriptome.txt
>TRINITY_DN261_c0_g1_i1 GATATTTATCCGAATATTCAATATGAT
>TRINITY_DN220_c0_g1_i1 GGGAGATAATAACAATGATAACACACAAAATTCCAATG
将very efficiently仅显示transcriptome.txt
中一行中第一行出现的selected_genes.txt
中的行。在我的测试中,这比其他方法要快得多。
答案 2 :(得分:0)
您的代码:
awk -F, 'FNR==NR{a[$1]=$1; next}; $1 in a {print a[$2]}'
将不起作用,因为您正在尝试打印不存在的a[$2]
。
更改为
awk -F, 'FNR==NR{a[$1]; next} $1 in a' selected_genes.txt transcriptome.txt
应该会给您预期的输出
第二个表达式是($1 in a) {print $0}
的缩写