2020-07-03 常用有趣命令之数据处理
2020-07-03 本文已影响0人
阿乜太帅
- 第一列相同时数据整理
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
- 输出某字符串的前三个字符
echo 123456|awk '{print substr($1,1,3)}'
14.for循环嵌套时避免重复运算,及自己比自己
for((i=1;i<=14;i++));
do
for((j=$i+1;j<=14;j++));
do
echo ${i}_vs_${j}
done
done
15.特殊情况下需要比较两列去重
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
16.大神整理的单行命令集合
bioinformatics-one-liners
17.行列转换
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 " " 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]; } }'
18.依据第一列做变量,相同时加和
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
19.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
20.跳过前两行,按照第一列数字,从大到小排序
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中各种括号的作用
21.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
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