三剑客 | awk

作者: shwzhao | 来源:发表于2021-10-24 16:57 被阅读0次

    我刚开始一直不理解 awk 的语法,后来看师兄的代码,加上天天敲,有了点提高。

    师兄在 2020-07-03 常用有趣命令之数据处理 中总结了很多代码,非常有用!
    我经常记不住,用到时就会进去复制下来。下面是一些简单基础的用法。


    1. 内置变量

    $0: 记录变量,表示当前正在处理的记录,理解为整行
    $n: 字段变量,其中n为整数,且 n 大于1,表示第 n 个字段的值,理解为第 n
    NF: 当前记录的字段数(number of field),理解为列数
    NR: 已经读入的记录数(number of record),理解为行数
    FS: 字段分隔符(field seperator),默认列分隔符为空白,awk -F "," 即可设置为 ,
    RS: 记录分隔符(record seperator);
    OFS: 输出字段分隔符;
    ORS: 输出记录分隔符;
    FILENAM: 正在处理的数据文件的名称;
    ARGIND: 实现多个文件的操作,可以参考:AWK实现多文件读取和处理awk打开多个文件的方法
    FNR: 当前文档的记录数,多文件操作时使用。

    • 去除最后一列
    awk '{$NF="";print}' a.txt
    

    尤其是每行列数不一样时,尤为实用,但每行最后会多出一个分隔符,可以用函数gsub(/.$/,"")进行删除,也可以用管道 | sed 's/.$//'

    • 多文件操作
      如:合并多个文件,并把每个文件的第一样去除
    awk '{if(FNR>1)print}' a.txt b.txt c.txt
    

    2. 运算符

    • 算术运算符
      +: 加;-: 减;*: 乘;/: 除

    • 赋值运算符
      +=: 将前后两个数值相加后的和赋给前面的变量
      -=: 将前后两个数值相减后的差赋给前面的变量
      */: 将前后两个数值的乘积赋给前面的变量
      /=: 将前后两个数值的商赋给前面的变量

    • 关系运算符
      ><>=<===!= 这些都不用说了

    • 逻辑运算符
      &&: 逻辑与,前后两个表达式的值全部为真时,其运算结果为真
      ||: 逻辑或,前后两个表达式只要有一个为真,其运算结果为真
      !: 逻辑非,表达式的值为假时,其运算结果为真

    • 三目运算符
      下面这个例子也用到了格式化输出

    >g1
    AGTCAT
    CATACG
    GCACTC
    AT
    >g2
    CCATCA
    TCAGGC
    C
    >g3
    ACCTTG
    GGCC
    
    $ awk '/^>/&&NR>1{print "";}{ printf "%s",/^>/ ? $0" ":$0 }' gene.fa
    >g1 AGTCATCATACGGCACTCAT
    >g2 CCATCATCAGGCC
    >g3 ACCTTGGGCC$
    

    可发现每个基因变成了一行两列,第一列为id,第二列为序列。
    加上| awk '{print $1"\n"}' 即可变成正常的单行 fasta 序列;
    若加上| awk '{a+=length($2)}END{print a}' 即可得出序列的大小。

    3. 函数

    • 字符串函数
      length(): 返回字符串的长度
      gsub(): 替换所有出现的子串
      substr(): 截取指定长度的子串。

    另外还有,字符串函数,index()match()split()sub();算术函数,int(x)sqrt(x)exp(x)...... 用不到,暂且留个印象。

    $ echo "0.9774563" | awk '{print int($1*10000+0.5)*0.01"%"}'
    97.75%
    

    4. 数组

    以下两行代码都是利用 数组 实现【转置】,代码是师姐网上找的,出处已经找不到了。

    awk '{for(i=1;i<=NF;i++){if(NR==1)res[i]=$i;else res[i]=res[i]" "$i}}END{for(j=1;j<=NF;j++){print res[j]}}' a.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}}' a.txt
    # 先是对每一个值按坐标进行定义数组,按坐标把相同列的排成行,太慢了
    

    Shell 的 join 命令可以联接多个文件,但需要进行排序,还总是会莫名报错,结果不可靠,awk 就很好使。

    $ cat a.txt
    gene2   noTF    others
    gene1   TF      MYB
    gene3   TF      HD-ZIP
    gene15  noTF    others
    $ cat b.txt
    gene10  23      9
    gene12  56      7
    gene3   75      8
    gene4   84      2
    gene1   50      3
    gene2   74      6
    
    $ awk 'BEGIN{OFS="\t"}ARGIND==1{a[$1]=$0}ARGIND==2{if($1 in a)print a[$1],$2,$3; else print $1,"NA\tNA",$2,$3}' a.txt b.txt
    gene10  NA      NA      23      9
    gene12  NA      NA      56      7
    gene3   TF      HD-ZIP  75      8
    gene4   NA      NA      84      2
    gene1   TF      MYB     50      3
    gene2   noTF    others  74      6
    

    5. 控制流

    日常 | 2021-05-10 | 任意n个样本表达量超过0.5视为表达 的一个例子:

    awk '{a=0;for(i=2;i<=NF;i++){if($i>0.5)a++};if(a>=2)print}' a.tsv
    

    相关文章

      网友评论

        本文标题:三剑客 | awk

        本文链接:https://www.haomeiwen.com/subject/akuzjltx.html