shell脚本(带循环)逐个grep一个字符串列表

时间:2016-10-16 07:51:34

标签: bash shell awk grep

我有一个大数据文本文件(超过100,000行),格式为:

0.000197239;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=CLCNKA;GeneDetail.refGene=.;ExonicFunc
0.00118343;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=CLCNKA;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.00276134;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=CLCNKA;GeneDetail.refGene=.;
0.0607495;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=CLCNKA;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.00670611;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=XDH;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.000197239;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=XDH;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.000394477;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=GRK4;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.0108481;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=GRK4;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.000394477;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=GRK4;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;
0.0108481;AN=192;NS=2535;ANNOVAR_DATE=2015-12-14;Func.refGene=exonic;Gene.refGene=GRK4;GeneDetail.refGene=.;ExonicFunc.refGene=nonsynonymous_SNV;

现在,每行包含一个基因名称,例如在最初的4行中有CLCNKA个基因。我使用grep命令来计算此数据文件中每个基因名称的频率,如下:

grep -w "CLCNKA" my_data_file | wc -l

在单独的文件中有大约300个基因要在上面的数据文件中搜索。有些专家可以写一个简单的shell script来循环从一个列表中逐一取基因名称,并将其频率存储在一个单独的文件中。所以,输出文件将是这样的:

CLCNKA    4
XDH    2
GRK4    4

7 个答案:

答案 0 :(得分:2)

awk是你的朋友

awk '{sub(/^.*Gene\.refGene=/,"");sub(/;.*$/,"");
     genelist[$0]++}END{for(i in genelist){print i,genelist[i]}}' file

<强>输出

GRK4 4
CLCNKA 4
XDH 2

旁注:这可能不会按照它们在文件中出现的顺序为您提供基因名称频率。我想这不是一个要求。

答案 1 :(得分:2)

你使我们感到困惑。我和其他一些人认为您想要的只是文件中每个基因的计数,因为您的输入/输出和一些描述性文本状态(count the frequency of each gene name in this data file)就是这样:

$ awk -F'[=;]' '{cnt[$11]++} END{for (gene in cnt) print gene, cnt[gene]}' file
GRK4 4
CLCNKA 4
XDH 2

虽然其他人都认为您想要计算存在于不同文件中的特定基因,因为这是您的主题行,提议的算法和其他文本的状态。

如果其他人都是对的,那么你需要这个调整来阅读&#34;基因&#34;首先归档并且只计算&#34;文件&#34;中的基因。在&#34;基因&#34;中列出:

awk -F'[=;]' 'NR==FNR{genes[$0]; next} $11 in genes{cnt[$11]++} END{for (gene in cnt) print gene, cnt[gene]}' genes file
GRK4 4
CLCNKA 4
XDH 2

您的示例没有帮助,因为它会产生相同的输出并解释您的要求,因此请编辑您的问题以阐明您想要的内容。特别是如果有一些您不想要计算的基因,那么请在样本输入中包含含有这些基因的行。

答案 2 :(得分:1)

这也可以在纯 bash 中完成,方法是使用associative array功能计算频率:

#!/bin/bash

# declare assoc array
declare -A freq

# split stdin input csv
for gene in $(cut -d ';' -f 6|cut -d = -f 2);do
    let freq[$gene]++
done

# loop over array keys
for key in ${!freq[@]}; do
    echo ${key} ${freq[$key]}
done

答案 3 :(得分:1)

依赖于 uniq 命令的更简单的解决方案:

#!/bin/bash

cut -d ';' -f 6|cut -d = -f 2|sort|uniq -c|while read -a kv;do
    echo  ${kv[1]} ${kv[0]}
done

答案 4 :(得分:0)

这是单行:

sed "s/.*Gene.refGene=//;s/\;.*//" test | sort | uniq -c | awk '{print $2,$1}'

sed - 将删除除基因名称以外的所有内容 sort将按名称进行排序 uniq -c - 将计算基因重复的数量 带有swap uniq输出的awk(默认为:计数模式)

答案 5 :(得分:0)

要保留订单,请按照示例中的说明对输入文件进行排序:

$ perl -lne '
($k) = /Gene\.refGene=([^;]+)/;
push(@o, $k) if !$h{$k}++;
END { print "$_\t$h{$_}" foreach (@o) }' ip.txt
CLCNKA  4
XDH     2
GRK4    4


如果没有,请使用哈希变量来增加用作键的基因名称和用于存储键顺序的数组

{{1}}

答案 6 :(得分:0)

如果你只搜索一个基因列表,这是一种低效但直截了当的方式

read g; do echo -n $g " "; grep -c $g file; done < genes

假设您的基因在基因文件中一次列出一个。

如果您的文件结构已修复,则更高效的版本将是

awk 'NR==FNR{genes[$1];next} 
            {sub(/Gene.refGene=/,"",$6)} 
 $6 in genes{count[$6]++} 
         END{for(g in count) print g,count[g]}' genes FS=';' file