#bash #shell #awk #grep
#bash #оболочка #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
gene . Я использую grep
команду для подсчета частоты каждого имени гена в этом файле данных, как:
grep -w "CLCNKA" my_data_file | wc -l
В отдельном файле содержится около 300 генов, которые необходимо искать в приведенном выше файле данных. Может ли какой-нибудь эксперт написать простой shell script
с циклом, чтобы брать имя гена из списка по одному и сохранять его частоту в отдельном файле. Итак, выходной файл будет выглядеть следующим образом:
CLCNKA 4
XDH 2
GRK4 4
Комментарии:
1. это больше работа для
awk
2. Итак, не могли бы вы предложить
awk
команду для этого, яawk
также редактирую тег.3. теперь, когда он помечен правильно, вам, вероятно, поможет какой-нибудь эксперт по awk.
Ответ №1:
Вы нас запутали. Я и некоторые другие думаю, что все, что вам нужно, это количество каждого гена в файле, поскольку это то, что ваш ввод / вывод и некоторые из ваших описательных текстовых состояний ( 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
в то время как все остальные думают, что вам нужно количество определенных генов, которые существуют в другом файле, поскольку это то, что указано в вашей теме, предлагаемом алгоритме и остальной части вашего текста.
Если все остальные правы, вам понадобится эта настройка, чтобы сначала прочитать файл «genes» и подсчитать только те гены в «файле», которые были перечислены в «genes»:
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
Ваш пример не помогает, поскольку он даст тот же результат при любой интерпретации ваших требований, поэтому отредактируйте свой вопрос, чтобы уточнить, чего вы хотите. В частности, если есть гены, которые вы НЕ хотите подсчитывать, то включите строки, содержащие их, во входной выборке.
Комментарии:
1. спасибо за твою заботу, дорогая. Да, второй случай верен, я хотел прочитать «гены» из отдельного файла, затем выполнить поиск в «файле данных», показанном выше, и вычислить встречаемость генов. Выходные данные будут представлять собой отдельный файл, как указано выше.
Ответ №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
Примечание: это может не дать вам частоту имен генов в том порядке, в котором они отображаются в файле. Я думаю, что это не является обязательным требованием.
Ответ №3:
Это также можно сделать в чистом bash, используя функцию ассоциативного массива для подсчета частот:
#!/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
Ответ №4:
Более простое решение, основанное на команде 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
Комментарии:
1. Нет необходимости в цикле и нет необходимости в 2
cut
секундах :awk -F'[;=]' '{print $11}' file | sort | uniq -c | awk '{print $2, $1}'
. Не предполагая, что вы должны делать это вместо 1 команды awk, конечно
Ответ №5:
Вот однострочный:
sed "s/.*Gene.refGene=//;s/;.*//" test | sort | uniq -c | awk '{print $2,$1}'
sed
— удалит все из строки, кроме имени гена
sort
будет выполнять сортировку по имени
uniq -c
— будет подсчитываться количество повторов гена
awk
с выводом swap uniq (по умолчанию это: шаблон подсчета)
Ответ №6:
Для сохранения порядка предоставленный входной файл сортируется так, как указано в примере:
$ perl -lne '
($g) = /Gene.refGene=([^;] )/;
if($g ne $p amp;amp; $. > 1)
{
print "$pt$c";
$c = 0;
}
$c ; $p = $g;
END { print "$pt$c" }' ip.txt
CLCNKA 4
XDH 2
GRK4 4
Если нет, используйте переменную hash для увеличения имени гена, используемого в качестве ключа, и массива для хранения порядка ключей
$ 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
Ответ №7:
если вы ищете только список генов, неэффективный, но простой способ
read g; do echo -n $g " "; grep -c $g file; done < genes
предполагая, что ваши гены перечислены по одному в файле 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