为什么在 bash 中使用 awk 就像在 Excel 中使用 vlookup 一样给出空输出文件?

Why using awk in bash like vlookup in Excel give empty output file?

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, Whosebug1,, Whosebug3,以及其他......)

所以我尝试使用这些线程的建议,但我的输出要么是空白,要么只是我的 selected_genes.txt 文件的副本。

我检查过,我的 2 个文件在 UTF-8CRLF 中。还有,

awk '{print }' `transcriptome.txt`
awk '{print }' `selected_genes.txt`

把我文件的第一列给我,所以问题不是出在他们身上。

这是我尝试过的:

awk -F, 'FNR==NR {a[]=; next};  in a {print a[]}' selected_genes.txt transcriptome.txt > output.txt
# Blank result

awk -F 'FNR==NR{var[]=;next;}{print var[]FS}' selected_genes.txt transcriptome.txt > output.txt
# Blank result

awk 'NR == FNR{a[] = ;next}; {print ,  in a?a[]: "NA"}' selected_genes.txt transcriptome.txt > output.txt
# Print only transcriptome.txt with first column and NAs

awk -F, 'FNR==NR{var[]=}FNR!=NR{print(var[]",")}' selected_genes.txt transcriptome.txt > output.txt
# Print only selected_genes.txt

我没有实现想要的输出。 任何能解释我的代码有什么问题的建议都将不胜感激。

盒子里有比 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 中一行的第一列的行。在我的测试中,这比其他方法快很多。

Awk 经典。将 千行 基因文件散列为一个散列 (a),以免浪费所有内存并从 十亿行 </code> 中查找 <code> =17=] 转录组文件:

$ awk '
    # { sub(/\r$/,"") }    # uncomment to remove Windows style line-endings.
    NR==FNR{a[]          # hash  of genes file to a
    next
}
( in a) {                # lookup from transcriptome
    print
}' genes transcriptome     # mind the order
>TRINITY_DN261_c0_g1_i1    GATATTTATCCGAATATTCAATATGAT
>TRINITY_DN220_c0_g1_i1    GGGAGATAATAACAATGATAACACACAAAATTCCAATG

您的代码:

awk -F, 'FNR==NR{a[]=; next};  in a {print a[]}' 

将不起作用,因为您正在尝试打印不存在的 a[]

改为

awk -F, 'FNR==NR{a[]; next}  in a' selected_genes.txt transcriptome.txt 

这应该会给你预期的输出

第二个表达式是 shorthand for ( in a) {print [=13=]}