grep -o '^>\S\+' test.fasta | less -S
grep -o '^>\S\+' test.fasta | grep -o '[^>]\+'
sed 中的正则表达式
echo -e "A B\n\nC\tD\n \nE" > testfile
#查看格式
vi testfile
:set list
#删除空行
sed '/^$/d' testfile
删除只有空格的行
sed '/^ \+$/d' testfile
删除所有无字符的行
sed '/^\s*$/d' testfile
替换所有以A开头的行为NA
sed 's/^A.*$/NA/' testfile
匹配以wangy开始,后面跟任意个小写字母的行
sed '/^wang[a-z]*/p' datafile.txt
-n 抑制默认空间的输出
匹配以wangy开始,后面跟1个或多个小写字母
sed -n '/^wangy[a-z]\+/p' datafile.txt
匹配以wangy开始,后面跟0个或1个小写字母
sed -n '/^wangy[a-z]\? /p' datafile.txt
匹配以wangy开始,后面跟3个小写字母
sed -n '/^wangy[a-z]\{3\} /p' datafile.txt
匹配以wangy开始,后面跟3-7个小写字母
sed -n '/^wangy[a-z]\{3,7\} /p' datafile.txt
匹配连续出现2次123的行
sed -n '/\(123\)\{2\}/p' datafile.txt
sed -n -r '/(123){2}/p' datafile.txt
使用分组及后向引用,交换表格第1列和第二列顺序
sed -r 's/^(\S+)\s+(\S+)/\2 \1/' datafile.txt
sed -r 's/^(\S+)(\s+)(\S+)/\3\2\1/' datafile.txt
3.4 sed 的多项编辑
对同一文件使用多条命令,可以使用一下三种方式实现:
-e ; -f
sed -e 's/wuhan/WUHAN/i' -e 's/beijing/BEIGING/i' datafile.txt
sed 's/wuhan/WUHAN/i ; s/beijing/BEIJ/i' datafile.txt
echo "s/wuhan/WUUHANN/i" >script.txt
echo "s/beijing/BEIJJJJ/i" >> script.txt
sed -f script.txt datafile.txt
使用大括号对同一地址范围使用多条命令
sed '1,4{ s/wuhan/WUHANNNN/i ; s/beijing/BEIJINGGGGG/i }' datafile.txt
sed -n '1,4{s/wuhan/WUHANNNNN/i ; s/beijing/BEIIIIII/i ; p}' datafile.txt
sed -n '1,4{s/wuhan/WU/i ; 2,3s/beijing/BEI/i ; p}' datafile.txt
sed -n '1,2s/^/test/p' datafile.txt
sed -n '1,2s/^\S\+{4}/test/p' datafile.txt
sed -n '1,2s/^/test/p' datafile.txt
sed -e '1,2s/wuhan/WUHAN/i' -e '1,2s/WUHAN/WUHANtest/i' datafile.txt
echo -e "1,2s/wuhan/WUHAN/i\n1,2s/WUHAN/WUHANtest/i" > script1.txt
sed -f script1.txt datafile.txt
sed -i '1,2s/wuhan/WUHAN/i' datafile.txt
sed -E 's/^wang\S+/test/' datafile.txt
sed -r 's/^wang\S+/test/' datafile.txt
基于 id 对应表格,将 fasta 文件中的基因 ID 替换成新 ID
sed -r 's:^(\S+)\s+(\S+)$:s/^>\2/>\1/:' id.table
s/// 可替换为界定符 s::: 效果是一样的
sed -r 's:^(\S+)\s+(\S+)$:s/^>\2/>\1/:' id.table > changeid.txt
sed -f changeid.txt test.fasta |less -S
AWK
内置变量 FS 中保存输入字段分隔符 -F(指定分隔符)
NF 中记录当前记录的字段个数 $NF 最后一列
awk '{print NF,$NF}' datafile.txt
awk -F '@' '{print NF , $1}' datafile.txt
输出字段分隔符 -v OFS=':'
默认的输出字段分隔符是 空格 即NF , $1之间的逗号,输出为空格
awk '{print NF , $1}' datafile.txt
awk -v OFS=':' '{print NF , $1}' datafile.txt
echo "hello"|awk '{print $0 "world"}'
echo "hello"|awk '{print $0 , "world"}'
echo "hello"|awk '{print $0 ; print "world"}'l
printf
echo 'hello world' | awk 'BEGIN {print "hello XXX"}'
echo -e 'helloworld\nHELLOWORLD' | awk '{printf $1}'
echo hello | awk '{printf "%s\n",$1}'
echo 1.2 | awk '{printf "%d\n",$1}'
echo 1.2 | awk '{printf "%f\n",$1}'
echo 1.2 | awk '{printf "%e\n",$1}' #科学计数法
echo 1.2 | awk '{printf "%e\n",$1}'
指定输出的宽度和对齐方式
echo "hello" |awk '{printf "[%10s]\n", $1}' #宽度10,默认右对齐
echo "hello" |awk '{printf "[%-10s]\n", $1}' #宽度10,指定左对齐
echo "1.2"| awk '{printf "[%6.2f]\n", $1}' #对浮点数设置宽度和精度
echo "hello" |awk '{printf "[%6.2s]\n", $1}' #对字符串设置宽度和精度
echo "hello" |awk '{printf "[%.2s]\n", $1}' #对字符串设置精度
echo "hello" |awk '{printf "[%-10.2s]\n", $1}' #对字符串设置宽度10和精度2
awk表达式:
echo "ABS" | awk '{a = $1 ; print a}'
echo "ABS" | awk '{a = $1 ; print $0 , a}'
echo "ABS" | awk '{a = $1 $1 ; print a}'
计算
echo "1 2" | awk '{a=$1;b=$2+1;avg=(a+b)/2;print avg}'
关系运算
布尔运算
awk '/wangying/' datafile.txt
awk '!/wangying/' datafile.txt
等价于
awk '$0 ~ /wangying/' datafile.txt
awk '$0 !~ /wangying/' datafile.txt
判断
逻辑判断 或|| 与&& 非 !
echo -e '10\n20\n30' > test1
awk '$1>25 || $1<15' test1
awk '$1>15 && $1<25' test1
awk '!($1>15)' test1
BEGIN模式 END模式
awk 'BEGIN{print "hello world"}'
echo -e '1\n2' | awk 'BEGIN{print "START"} {print $0}'
echo -e '1\n2\n3\n4' | awk '{s = s + $1 ; print s}'
echo -e '1\n2\n3\n4' | awk '{s = s + $1} END {print "SUM=" s}'
if判断
echo '1 2'
echo '1 2' | awk '{if($1<$2) {print$1 ;print$1+$2}}'
echo '1 2' | awk '{if($1<$2) {a=$1+$2 ; print$1; print a}}'
echo -e '1 2\n4 3'
echo -e '1 2\n4 3' | awk '{if ($1<$2) {print $1} else {print $2}}'
echo -e '1 2\n4 3\n5 5' |\
awk '{if ($1<$2){print $2} \
else if($1==$2) {print "eq"} \
else {print $1}}'
for 循环
echo -e '1 2 3\n4 5 6' |\
awk '{for(i=1;i<=3;i++) {sum = sum + $i } ; print "sum=" sum}'
数组
echo -e "1 2 3\n4 5 6"|\
awk '{A[NR] = $1+$2+$3} END {for(i=1;i<=NR;i++) {print i,A[i]}}'
echo -e "1 2 3\n4 5 6"|\
awk '{A[NR] = $1+$2+$3} END {for(i in A) {print i,A[i]}}'
echo -e "1 2 3\n4 5 6"|\
awk '{A[NR] = $1+$2+$3}\
END {for(i=1;i<=NR;i++){print i,A[i];sum=sum+A[i]};{print "sum=" sum}}'
echo -e '1 2 3\n4 5 6' |\
awk '{A[NR]=$1} END {if(2 in A){print 2,A[2]}}'
内置函数
计算字符串长度 length
echo 'ABC abc' |awk '{print length($1)}'
字符串替换函数sub与gsub
echo 'ABC abc' | awk '{sub(/B/,"b",$1) ;print$0}'
echo 'ABC abc' | awk '{sub(/[A-Z]/,"U",$0) ;print$0}'
echo 'ABC abc' | awk '{sub(/[A-Z]+/,"U",$0) ;print$0}'
echo 'ABC abc' | awk '{gsub(/[A-Z]/,"U",$0) ;print$0}'
echo 'ABC abc' | awk '{gsub(/[A-Z]+/,"U",$0) ;print$0}'
echo 'ABC abc' | awk '{gsub(/[a-zA-Z]/,"*",$0) ;print$0}'
echo 'ABC abc' | awk '{gsub(/[a-zA-Z]+/,"*",$0) ;print$0}'
提取字符串substr
substr(字符串,起始位置)
substr(字符串,起始位置,长度)
提取第三个字符开始长度为2的子串
echo "abcdefg" |awk '{ print substr($1,3,2)}'
指定的长度超过字符实际范围,则返回实际长度
echo "abcdefg" |awk '{ print substr($1,3,10)}'
省略长度时,返回指定位置开始到结尾的子串
echo "abcdefg" |awk '{ print substr($1,3)}'
切分字符串成数组 split
split(字符串, 数组,分隔符)
echo "ABC abc"|awk '{ n=split($0,uu," ") ; print n, uu[1],uu[2]}'
echo "ABC abc"|awk '{ split($0,uu," ") ; print uu[1],uu[2]}'
内置算数函数
int 函数
awk 'BEGIN{print int(10.056)}'
log函数和exp函数
awk 'BEGIN{print log(10),exp(10)}'
rand和strand函数
awk 'BEGIN{print rand()}'
awk 'BEGIN{srand(12);print rand()}'
实战一:计算 fasta 文件每条序列长度及总长
less -S test.fasta | awk '{if ($1 ~ /^>/) \
{if(NR>1){print ""};printf $1"\t" } else {printf $1}}' \
| awk '{print $1,length($2)}' |sed 's/^>//' \
| awk '{print ;sum += $2} END {print "total_length=" ,sum}'
方法二
less -S test.fasta | awk '{if ($1 ~ />/)\
{{print id,len};id=$1;len=0} else {len+=length($1)}}\
END{print id,len}' | sed 's/>//'\
|awk '{print ;sum+=$2}END{print "total_length=",sum}'
实战二:统计 gff3 文件每个转录本长度。测试数据为拟南芥 1 号染色体
gff3 文件。
less -S test.gff3 | \
awk '$3 ~ /exon/' | \
sed -r 's/^(.*Parent=([^;]+);.*)$/\2\t\1/'|\
awk '{print $1,$6-$5+1}'|\
awk '{A[$1]=A[$1]+$2} END {for(id in A) {print id,A[id]}}'
统计gff3 文件每个转录本的exon数量
less -S test.gff3 | \
awk '$3 ~ /exon/' | \
sed -r 's/^(.*Parent=([^;]+);.*)$/\2/'|sort |uniq -c|
less -S test.gff3 | \
awk '$3 ~ /exon/' | \
sed -r 's/^(.*Parent=([^;]+);.*)$/\2/'|\
awk '{A[$1]=A[$1]+1} END {for(id in A) {print id,A[id]}}'|less -S
总结