- 第一列相同时数据整理
input:
A 12 9
A -0.3 2.3
B 1.0 -4
C 34 1000
C -111 900
C 99 0.09
Output required:
A 12 9 -0.3 2.3
B 1.0 -4
C 34 1000 -111 900 99 0.09
Five codes:
sort inputfile | awk '{if(a!=$1) {a=$1; printf "\n%s%s",$0,FS} else {a=$1;$1="";printf $0 }} END {printf "\n" }'
awk '{a[x++]=$0;b[xx++]=substr($0,1,1)}END{for(i=0;i<x;i++)if(b[i]==b[i+1]){f=f?f a[i+1]:f a[i]a[i+1]}else{if(f=="")f=a[i];gsub(b[i]" ","",f); print b[i] f;f=""}}' unsorted.inputfile
sort inputfile |awk '$1!=p{if(p)print s; p=$1; s=$0; next}{sub(p,x); s=s $0} END{print s}'
awk '{k=$1=$1; sub(k,x); A[k]=A[k] $0} END{for(i in A)print i A[i]}' unsorted.inputfile
sort inputfile | awk '{a[$1]=a[$1]?a[$1]" "$2:$2}END{for (i in a) print i,a[i]}' #仅适合两列的数据类型
2.某列相同时只保留某列最大的那一行
Output required:
#第一列相同时,保留第二列最大的一行
A 12 9
B 1.0 -4
C 99 0.09
sort -k1,1 -k2,2nr inputfile |awk '!a[$1]++{print}'
3.最强多行变一行
awk 'BEGIN{FS=RS;RS=KS}$1=$1'
awk '{ORS="\t";$1=$1; print $0}'
4.求某列数据的标准差,方差,均值,样本数(行数)
echo "6,3
> 2,4,5
> 5,a,6
> 3,5,4
> 4,4,5">ppp
awk -F "," '{print $1}' ppp| awk '{x[NR]=$0; s+=$0; n++} END{a=s/n; for (i in x){ss += (x[i]-a)^2} sd = sqrt(ss/n); print "SS""\t"sd,ss,a,n}'
SS 1.41421 10 4 5
#多列同时求和,此例求一三列
awk '{FS = OFS = "," }{sum1 += $1; sum2 += $3}END { print sum1, sum2 }' ppp
5.替换
sed -e 'y/ATCG/atcg/' seq.fna #对应替换之修改大小写
sed -e '/>/!y/ATCG/atcg/' seq.fna #对应替换之DNA序列反向互补配对,并修改大小写
sed '100,2000s/GI/gi/g' seq.fa #则只替换100行到2000行的内容;
sed '100,2000!s/GI/gi/g' seq.fa #加感叹号取反,在这个范围之外的执行操作;
sed 's/:.*//g' seq.fna #删除冒号之后的所有内容;
sed 's/gi/GI/' seq.fna #将文件中gi全部替换为大写GI;
sed 's/\<gi\>/GI/' seq.fna #精准替换,不会把agiii替换为aGIii;
sed -i 's/gi/GI/g' seq.fna #在原文件上进行替换,并且进行全部替换;
sed -i.bak 's#GI#gi#' seq.fna #在原文件上进行替换,并进行备份;
sed -e 's/gi/GI/2;s/ref/REF/2' seq.fna #只将第二次出现的gi和ref进行替换;
sed -f sed.list cds.list #根据文件中的模式进行替换,可同时进行多条件替换;
sed -n 's/gi/GI/p' seq.fna #打印发生替换的行;
awk '{sub(/test/, "no", $0);print}' input.txt #进行替换,类似sed的功能。
6.输出行
sed -n '1307p' seq.fna #输出文件第1307行;
sed -n '100,200' seq.fna #输出文件第100到200行;
sed -n '/ref/p' seq.fna #输出文件中包含ref关键字的行;
awk ’{if ($3>=80 && $4>=100) print $0}' blast_m8.out #过滤blast比对结果,将identity 大于80,并且比对长度大于100bp的结果输出;
awk '$0~ /wang/{print $0}' passwd.list #利用正则表达式,将秘密表中姓wang的账户都输出出来;
awk 'NR>=20&&NR<=80' input.txt #输出第20到第80行内容。
7.输出列
awk -F ":" '{print $1,$NF}' passwd.list #通过-F修改默认分隔符为冒号,输出第一行与最后一行;
8.去重
sort -u file;
sort file|uniq;
uniq -d file #仅显示重复出现的行列,显示一行。
uniq -D file #显示所有重复出现的行列,有几行显示几行。
uniq -u file #仅显示出一次的行列
uniq -s N file #忽略比较前面的N个字符。
uniq -w N file #对每行第N个字符以后的内容不作比较。
awk '!($0 in a) {a[$0];print}' input.txt # 打印不重复的行,类似uniq的功能;
awk '!($2 in l){print;l[$2]=1}' input.txt #计算第二列内容非冗余的次数,类似于uniq的功能。
sort file|uniq -c |awk '{if($1==3) print $0}' #提取重复三次的项
9.一行变多行
input:
A 12 9;-0.3 2.3
B 1.0 -4
C 34 1000;-111 900;99 0.09
Output required:
A 12 9
A -0.3 2.3
B 1.0 -4
C 34 1000
C -111 900
C 99 0.09
sed -r '/;/s/(\S+)\s+([^;]+);/\1 \2\n\1 /;P;D' input > Output
10.awk浮点数计算要双精度校准才能保证真正准确,尤其是在小数点后9位以后。因为awk的默认精度范围是53bit,也就是双精度的范围内,因此在做高精度数值计算时,一定要注意浮点数的精度要求。
#不加双精确
echo 57760731.179959 | awk '{sum+=$1}END{printf("%.10f\n",sum)}'
57760731.1799589992
#加双精度
echo 57760731.179959 | awk -M -v PREC=100 -v CONVFMT=%.30g '{sum+=$1}END{printf("%.10f\n",sum)}'
57760731.1799590000
11.保留两位小数
#awk-仅一列数据
echo '4.667,9.888
3.442,3.44203
3.2214,4.302' > input
#awk-只第一列
awk '{printf "%.2f\n",$1}' input
#awk-两列同时
awk '{num1=sprintf("%.2f",$1); num2=sprintf("%.2f",$2);print num1,num2}' input
#awk,常规print,很巧妙的利用int
awk '{print int($1*100)/100,$2}'
#bc
echo "scale=2;3/8" |bc #scale=2将小数位个数设置为2
0.37
12.两文件取交集
gawk 'ARGIND==1{a[$1]=$1} ARGIND==2{if(a[$1]!="") print $0}' geneid.txt tpm.txt > gene.tpm.txt
awk 'NR==FNR{a[$1]=$0}NR>FNR{if($1 in a)print a[$1]"\t"$0}' A B > C
awk 'NR==FNR{a[$1]=$0;next}{if ($1 in a){print a[$1]"\t"1} else {print $0"\t"0}}' A B > C
grep -w -A 1 -Ff genename gene.fasta --no-group-separator > genename.fasta
13.两文件取差集、并集、交集
echo "a
b
c
d" > a
echo "b
c
d
e
f"> b
#交集
sort a b | uniq -d
b
c
d
#并集
sort a b| uniq
a
b
c
d
e
f
#差集
#a特有
sort a b b | uniq -u
a
#b特有
sort b a a | uniq -u
e
f
- 输出某字符串的前三个字符
echo 123456|awk '{print substr($1,1,3)}'
15.for循环嵌套时避免重复运算,及自己比自己
for((i=1;i<=14;i++));
do
for((j=$i+1;j<=14;j++));
do
echo ${i}_vs_${j}
done
done
16.特殊情况下需要比较两列去重
echo "1 2
2 1
1 1
2 4">input
cat input| awk '$1 != $2'
1 2
2 1
2 4
sort input| awk '!(SEEN[$1,$2]++) && !(($2,$1) in SEEN)'
1 2
2 4
17.大神整理的单行命令集合
bioinformatics-one-liners
18.行列转换
#输出的分隔符有点乱
cat file.txt | awk 'BEGIN{c=0;} {for(i=1;i<=NF;i++) {num[c,i] = $i;} c++;} END{ for(i=1;i<=NF;i++){str=""; for(j=0;j<NR;j++){ if(j>0){str = str" "} str= str"\t"num[j,i]}printf("%s\n", str)} }'
#推荐
cat file.txt | awk '{for(i=1;i<=NF;i=i+1){a[NR,i]=$i}}END{for(j=1;j<=NF;j++){str=a[1,j];for(i=2;i<=NR;i++){str=str "\t" a[i,j]}print str}}'
#最慢
cat file.txt | awk '{ for(i=1;i<=NF;i++){ if(NR==1){ arr[i]=$i; }else{ arr[i]=arr[i]"\t"$i; } } } END{ for(i=1;i<=NF;i++){ print arr[i]; } }'
19.依据第一列做变量,相同时加和或者求均值
input:
A 12
A 3
B 1
C 34
C 11
C 99
求和
Output required:
A 15
B 1
C 144
awk '{s[$1] += $2}END{ for(i in s){ print i, s[i] } }' input
求均值
Output required:
A 7.5
B 1
C 48
awk '{sum[$1]+=$2; count[$1]++} END {for (key in sum) {if (count[key]>1) {avg=sum[key]/count[key]; print key, avg} else {print key, sum[key]}}}' input.txt
20.awk求一列数的均值,最大值,最小值,中位数
input:
12
3
1
34
11
99
Output required:
mean: 26.6667
max: 99
min: 1
median: 12
sort -n input | awk '{m[i++]=$1;if(min==""){min=max=$1}; if($1>max) {max=$1}; if($1<min) {min=$1}; total+=$1; count+=1} END {print "mean:\t" total/count,"\nmax:\t"max,"\nmin:\t"min,"\nmedian:\t "m[int(i/2)]}'
#表达矩阵,提取N个样本均值大于0.5的基因
awk '{a=0;for(i=2;i<=NF;i++){if($i>0.5)a++};if(a>=2)print}' a.tsv
#计算变异系数
awk '{ sum += $1; sumsq += ($1)^2; n++ } END { mean = sum / n; sd = sqrt((sumsq - sum^2/n) / (n - 1)); cv = sd / mean * 100; print cv }' data.txt | bc
21.跳过前两行,按照第一列数字,从大到小排序
echo "G C N
3 b D
1 2 9
5 2 3
2 3 4" > input
Output required:
G C N
3 b D
5 2 3
2 3 4
1 2 9
(awk 'NR<3' input && awk 'NR>2' input| sort -k1,1nr) > output
其实这个命题引出了shell里括号的用法,这里的小括号将命令做成了命令组,括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用。 更多相关知识可见:shell中各种括号的作用
22.for循环1到10
for i in `echo 1 2 3 4 5 6 7 8 9 10`;do echo "${i}";done
for i in `seq 10`;do echo "${i}";done #10可为参数传递
for i in $(seq 1 1 10);do echo "${i}";done #10可为参数传递
for i in {1..10..1};do echo "${i}";done
for i in {1..10};do echo "${i}";done
23.几种bed文件的sort策略
sortBed -i input.bed
bedtools sort -i input.bed
sort -k 1,1 -k2,2n input.bed
sort -V -k 1,3 input.bed
sort -V -k 1,1 -k2,2n input.bed #通常这个最好用
-V参数重要, --version-sort natural sort of (version) numbers within text
24.python模块安装
python2 -m pip install biopython --user
# in a virtual environment or using Python 2
pip install biopython
# for python 3 (could also be pip3.10 depending on your version)
pip3 install biopython
# if you get permissions error
sudo pip3 install biopython
pip install biopython --user
# if you don't have pip in your PATH environment variable
python -m pip install biopython --user
# for python 3 (could also be pip3.10 depending on your version)
python3 -m pip install biopython --user
# using py alias (Windows)
py -m pip install biopython
# for Anaconda
conda install -c conda-forge biopython
# for Jupyter Notebook
!pip install biopython
25.perl 模块安装
#非root用户。推荐运行下面的代码获取自己的私人cpan下载器。
wget -O- http://cpanmin.us | perl - -l ~/perl5 App::cpanminus local::lib
eval `perl -I ~/perl5/lib/perl5 -Mlocal::lib`
echo 'eval `perl -I ~/perl5/lib/perl5 -Mlocal::lib`' >> ~/.bashrc
echo 'export MANPATH=$HOME/perl5/man:$MANPATH' >> ~/.bashrc
#完成以上操作后以后只需要运行以下命令即可
cpanm Convert::Color
# 不区分大小写、加上了perl前缀、中间以短横线连接
conda install -c bioconda perl-convert-color
26.输出当下系统时间
echo $(date +%Y-%m-%d" "%H:%M:%S)
27.整行均值过滤(跳过第一列)
cutvalue=`echo 1`
awk -vcut="${cutvalue}" '{a=0;for(i=2;i<=NF;i++){if($i>cut)a++};if(a>=2)print}' matrix.tsv
28.分组求均值
示例里是5个分组(sample)*5次重复的数据示例
修改的话,可按:6个时间点,每个时间点3个重复,改为-v sample=6 -v repeat=3即可。
awk -v sample=5 -v repeat=5 '{for(i=1;i<=sample;i++){I=(i-1)*repeat;sum=0;for(j=1;j<=repeat;j++){sum+=$(I+j+1)};if(allsum[$1]=="")allsum[$1]=$1"\t"sum/repeat; else allsum[$1]=allsum[$1]"\t"sum/repeat}}END{for(k in allsum)print allsum[k]}' a.tpm.tsv
gene1 0 0.007919 0.0417744 436.062 833.515
gene2 83.9412 21.8847 45.4605 86.878 70.9082
gene3 11.1208 2.56975 7.76237 12.7182 11.5676
29.shell下按列名处理文件
使用bioawk软件
$ cat b.txt
geneid T1_1 T1_2 T1_3 T2_1 T2_2 T2_3
gene1 1 3 9 2 8 5
gene2 3 4 5 8 0 8
$ bioawk -t -c header '{print $geneid,$T1_1,$T2_1}' b.txt
geneid T1_1 T2_1
gene1 1 2
gene2 3 8
使用awk,但是很绕
$ awk 'BEGIN{OFS="\t"}NR==1{for(i=1;i<=NF;i++){a[$i]=i}}NR>=1{print $a["geneid"],$a["T1_1"],$a["T2_1"]}' b.txt
geneid T1_1 T2_1
gene1 1 2
gene2 3 8
30.awk来做长数据和宽数据之间的转换
echo "a|A|10
a|B|0
b|C|10" |sed 's/|/\t/g' > test.long
cat test.long | awk -F'\t' '{data[$2][$1]=$3; samples[$1]} END {header="id"; for(sample in samples){header=header"\t"sample} print header; for(gene in data){output=gene; for(sample in samples){output=output"\t"(data[gene][sample]?data[gene][sample]:"0")} print output}}' > test.long2wide
cat test.long2wide | awk -F'\t' 'NR==1{for(i=1; i<=NF;i++){headers[i] = $i}}NR>1{for(i = 2; i <= NF; i++) {print $1 "\t" headers[i] "\t" $i}}' > test.wide2long
reference:
https://www.unix.com/shell-programming-and-scripting/188147-how-merge-multiple-rows-into-single-row-if-first-column-matches.html
https://mp.weixin.qq.com/s/FTi2PwMlDdmWsn2Db71uSA
//www.greatytc.com/u/e86db5f5bbb8