语法格式:

格式1:command | awk [选项] ‘BEGIN{指令}[条件]{指令}END{指令}’

格式2:awk [选项] ‘BEGIN{指令}[条件]{指令}END{指令}’ 文件

内置变量

表达式 含义
NR 行号
NF 每行列的总数
FS 字段分隔符,用法:-vFS=separator
OFS 输出字段分隔符, 用法:-vOFS=separator
FNR 记录当前行的行号



RS:读取分隔符,默认是按行读取
RS=””:按空行为分隔符读取
RS=”reg”:按照reg为分隔符读取
RS=”^$”:一次性读取所有的数据
RS=”\n+”:按行读取,但忽略所有的空行
-F: 指定字段分隔符,默认的空格,tab
$0 整行
$1 第一列
$2 第二列
$3 第三列
$NF 最后一列

运算符

算数运算符

+、-、、/、%、++、—、+=、-=、=、/=

+:浮点数运算

  1. Desktop awk 'BEGIN{a=2.5;b=3.25;print a+b}'
  2. 5.75

+=:统计文本的字段数

  1. Desktop awk -F':' 'BEGIN{sum=0}{sum+=NF}END{print sum}' /etc/passwd
  2. 119

++:统计以bash结尾的个数

  1. Desktop awk 'BEGIN{sum=0}/\<bash$/{sum++}END{print sum}' /etc/passwd
  2. 1

逻辑运算符

&&:期望多个条件都成立

  1. # 列出第三个字列的值是1-8的行
  2. Desktop awk -F':' '$3 >= 1 && $3 <= 8 {print}' /etc/passwd
  3. bin:x:1:1::/:/usr/bin/nologin
  4. daemon:x:2:2::/:/usr/bin/nologin
  5. mail:x:8:12::/var/spool/mail:/usr/bin/nologin

||:只要有一个条件满足就输出

  1. # 输出第三列的值是1或者8的行
  2. Desktop awk -F':' '$3 == 1 || $3 == 8 {print}' /etc/passwd
  3. bin:x:1:1::/:/usr/bin/nologin
  4. mail:x:8:12::/var/spool/mail:/usr/bin/nologin

正则

/content/:过滤含有content的行

  1. # 过滤含有root的行
  2. Desktop awk '/root/{print}' /etc/passwd
  3. root:x:0:0::/root:/bin/bash

/content1/,/content2/:读取一段文本,从content1开始过滤,过滤到content2

  1. # 从root过滤到daemon
  2. Desktop awk '/root/,/daemon/{print}' /etc/passwd
  3. root:x:0:0::/root:/bin/bash
  4. bin:x:1:1::/:/usr/bin/nologin
  5. daemon:x:2:2::/:/usr/bin/nologin

打印某个字段以bash结尾的行

  1. # 打印第7个字段是以bash结尾的行
  2. Desktop awk -F':' '$7~/bash$/{print $7}' /etc/passwd
  3. /bin/bash

打印某个字段不以bash结尾的行

  1. # 打印第7个字段是不以bash结尾的行
  2. Desktop awk -F':' '$7!~/bash$/{print $7}' /etc/passwd
  3. /bin/bash

流程控制

单分支:if(){}

  1. # 统计第三列的数值大于等于500的个数
  2. Desktop awk -F':' 'BEGIN{sum=0}{if($3 >= 500) {sum++}}END{print sum}' /etc/passwd
  3. 9

双分支:if(){}else{}

  1. # 统计大于等于500的个数, 小于500的个数
  2. Desktop awk -F':' 'BEGIN{i;j}{if($3 >= 500) {i++} else {j++}}END{print "大于等于500的个数:"i",小于500的个数:"j}' /etc/passwd
  3. 大于等于500的个数:9,小于500的个数:8

多分支:if(){}else if{}else{}

  1. # 统计第三列小于500的个数,500-1000的个数据,大于1000的个数
  2. Desktop awk -F':' 'BEGIN{a;b;c}{if($3 <= 500) {a++} else if($3 <= 1000){b++} else {c++}}END{print "小于等于500的个数:"a",500-1000之间的个数:"b",大于1000的个数:"c}' /etc/passwd
  3. 小于等于500的个数:8500-1000之间的个数:8,大于1000的个数:1

循环结构

while(条件){循环体}

  1. # 统计root单词的个数
  2. Desktop awk -F ":|/" 'BEGIN{sum}{while(i<=NF){if($i==root){sum++};i++}}END{print sum}' /etc/passwd
  3. 5

for(初值;条件;步长){循环体}

  1. # 打印10以内的基数
  2. Desktop awk 'BEGIN{for(i=0;i<=10;i++){if(i%2==1){print i}}}'
  3. 1
  4. 3
  5. 5
  6. 7
  7. 9

for(key in arr){循环体}

  1. # 统计每个单词的个数
  2. Desktop awk -F':|/' '{for(i=1;i<=NF;i++){if($i~/^$/){continue};arr[$i]++}}END{for(key in arr){print key,arr[key]}}' /etc/passwd | sort -rn -k2 | head
  3. bin 18
  4. x 17
  5. usr 15
  6. nologin 14
  7. sunzhengbo 2
  8. srv 2
  9. root 2
  10. mail 2
  11. http 2
  12. ftp 2
  13. Desktop awk -F':|/' '{for(i=1;i<=NF;i++){if($i~/^$/){continue};arr[$i]++}}END{PROCINFO["sorted_in"]="@val_num_desc";for(key in arr){if(counter++==10){exit}print key,arr[key]}}' /etc/passwd
  14. bin 18
  15. x 17
  16. usr 15
  17. nologin 14
  18. sunzhengbo 2
  19. srv 2
  20. root 2
  21. mail 2
  22. http 2
  23. ftp 2

流程控制关键字

关键字 含义
break 结束当前的循环体
continue 结束当次循环,进入下次循环
next 跳过当前行,读取下一行,如:awk ‘NF<2{next}{print}’ xxx.log
exit 结束文本读取,转入END{}

数组

image.png

进阶

去重

  1. Desktop awk -F'/' '{arr[$NF]++;if(arr[$NF]==1){print}}' /etc/passwd
  2. root:x:0:0::/root:/bin/bash
  3. bin:x:1:1::/:/usr/bin/nologin
  4. git:x:975:975:git daemon user:/:/usr/bin/git-shell
  5. sunzhengbo:x:1000:1000::/home/sunzhengbo:/bin/zsh
  6. # 可以简写为:
  7. # arr[key]不存在的情况下执行++是false,再取反就是true,
  8. # 后面再执行就变成true,取反是false,所以起到去重的作用
  9. Desktop awk -F'/' '!arr[$NF]++' /etc/passwd
  10. root:x:0:0::/root:/bin/bash
  11. bin:x:1:1::/:/usr/bin/nologin
  12. git:x:975:975:git daemon user:/:/usr/bin/git-shell
  13. sunzhengbo:x:1000:1000::/home/sunzhengbo:/bin/zsh

指定分隔符

➜  Desktop awk 'BEGIN{FS="/"}{arr[$NF]++;if(arr[$NF]==1){print}}' /etc/passwd
root:x:0:0::/root:/bin/bash
bin:x:1:1::/:/usr/bin/nologin
git:x:975:975:git daemon user:/:/usr/bin/git-shell
sunzhengbo:x:1000:1000::/home/sunzhengbo:/bin/zsh

插入字符

➜  Desktop echo 'a b e' | awk '{$2=$2" c d";print}'
a b c d e

# 修改字段后会重建$0的OFS
➜  Desktop echo 'a         b        e' | awk '{$2=$2" c d";print}'
a b c d e

格式化输出

  1. 设置输出分隔符
  2. 必须修改字段,因为修改字段才会使OFS生效
    ➜  Desktop echo 'a b c d e\naa bb cc dd ee\naaa bbb cc d e' | awk 'BEGIN{OFS="\t"}{$1=$1;print}'
    a       b       c       d       e
    aa      bb      cc      dd      ee
    aaa     bbb     cc      d       e
    

    按段落读取

    mdatacenter_every_month_data.txt
    ➜  Desktop awk 'BEGIN{RS="project";sum=0}NR>1{result=$8*$NF;print $2$8" * "$NF" = "result"M";sum+=result}END{print "total = "sum/1024"G"}' mdatacenter_every_month_data.txt
    50 * 92.141M = 4607.05M
    23 * 226.252M = 5203.8M
    24 * 315.571M = 7573.7M
    81 * 158.543M = 12842M
    2 * 11.481M = 22.962M
    39 * 211.513M = 8249.01M
    42 * 48.530M = 2038.26M
    20 * 150.899M = 3017.98M
    20 * 189.790M = 3795.8M
    32 * 147.368M = 4715.78M
    20 * 167.853M = 3357.06M
    19 * 164.603M = 3127.46M
    48 * 182.207M = 8745.94M
    16 * 159.386M = 2550.18M
    21 * 144.483M = 3034.14M
    15 * 138.930M = 2083.95M
    15 * 191.698M = 2875.47M
    95 * 142.026M = 13492.5M
    238 * 170.142M = 40493.8M
    19 * 152.516M = 2897.8M
    2 * 2372.505M = 4745.01M
    total = 136.201G
    

    替换:

    gsub:全局替换

    gsub(r,s) 在整个$0中用s替代r
    gsub(r,s,t) 在整个t中用s替代r

    sub:仅替换第一次匹配的内容

    sub (regular expression, substitution string)
    sub (regular expression, substitution string, target string)
    ➜  Desktop awk 'BEGIN{RS="project";sum=0}NR>1{result=$8*$NF;gsub(",",": ", $2);print $2 $8" * "$NF" = "result"M";sum+=result}END{print "total = "sum/1024"G"}' mdatacenter_every_month_data.txt
    郝家营: 50 * 92.141M = 4607.05M
    太和仙: 23 * 226.252M = 5203.8M
    武川: 24 * 315.571M = 7573.7M
    呱呱山: 81 * 158.543M = 12842M
    雅培: 2 * 11.481M = 22.962M
    睢宁魏集核源: 39 * 211.513M = 8249.01M
    广西灵山: 42 * 48.530M = 2038.26M
    仰天湖二期: 20 * 150.899M = 3017.98M
    五寨: 20 * 189.790M = 3795.8M
    北山梁: 32 * 147.368M = 4715.78M
    虞城: 20 * 167.853M = 3357.06M
    丰顶山: 19 * 164.603M = 3127.46M
    尖尖山: 48 * 182.207M = 8745.94M
    龙潭: 16 * 159.386M = 2550.18M
    新野: 21 * 144.483M = 3034.14M
    火木梁: 15 * 138.930M = 2083.95M
    龙门: 15 * 191.698M = 2875.47M
    太仆寺旗: 95 * 142.026M = 13492.5M
    乌达来: 238 * 170.142M = 40493.8M
    上蔡: 19 * 152.516M = 2897.8M
    成都领克: 2 * 2372.505M = 4745.01M
    total = 136.201G
    

    awk 换行书写

    ```bash ➜ Desktop awk ‘ BEGIN{ RS=”project” sum=0 }

NR>1{ result=$8$NF sub(“,”, “:\t”, $2) print $2 $8” “$NF” = “result”M” sum+=result }

END{ print “total: “sum/1024”G” } ‘ mdatacenter_every_month_data.txt 郝家营: 50 92.141M = 4607.05M 太和仙: 23 226.252M = 5203.8M 武川: 24 315.571M = 7573.7M 呱呱山: 81 158.543M = 12842M 雅培: 2 11.481M = 22.962M 睢宁魏集核源: 39 211.513M = 8249.01M 广西灵山: 42 48.530M = 2038.26M 仰天湖二期: 20 150.899M = 3017.98M 五寨: 20 189.790M = 3795.8M 北山梁: 32 147.368M = 4715.78M 虞城: 20 167.853M = 3357.06M 丰顶山: 19 164.603M = 3127.46M 尖尖山: 48 182.207M = 8745.94M 龙潭: 16 159.386M = 2550.18M 新野: 21 144.483M = 3034.14M 火木梁: 15 138.930M = 2083.95M 龙门: 15 191.698M = 2875.47M 太仆寺旗: 95 142.026M = 13492.5M 乌达来: 238 170.142M = 40493.8M 上蔡: 19 152.516M = 2897.8M 成都领克: 2 * 2372.505M = 4745.01M total: 136.201G

<a name="QARzd"></a>
### 调用系统命令
awk也是一种语言,所以不能直接在awk中直接使用系统命令,需要使用system()才能执行系统命令
<a name="O64Gq"></a>
#### 批量修改文件名
```bash
$ find $PWD -name "m*" | awk -vFS=/ -vOFS=/ '{raw=$0;sub("m", "M", $NF);c="mv "raw" "$0; print c; system(c)}'
mv /d/Backup/bjwater/machines.bson /d/Backup/bjwater/Machines.bson
mv /d/Backup/bjwater/machines.metadata.json /d/Backup/bjwater/Machines.metadata.json
mv /d/Backup/bjwater/measurements.bson /d/Backup/bjwater/Measurements.bson
mv /d/Backup/bjwater/measurements.metadata.json /d/Backup/bjwater/Measurements.metadata.json