awk 使用笔记

基础语法说明

awk 是按分割符进行行处理的工具

1. 命令参数说明

$ awk
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:          GNU long options: (standard)
        -f progfile             --file=progfile   从脚本文件中读取awk命令
        -F fs                   --field-separator=fs   指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F ‘|’
        -v var=val              --assign=var=val    赋值一个用户定义变量
Short options:          GNU long options: (extensions)
        -b                      --characters-as-bytes
        -c                      --traditional
        -C                      --copyright
        -d[file]                --dump-variables[=file]
        -D[file]                --debug[=file]
        -e 'program-text'       --source='program-text'
        -E file                 --exec=file
        -g                      --gen-pot
        -h                      --help
        -i includefile          --include=includefile 加载导入文件
        -l library              --load=library  加载 awk 库
        -L[fatal|invalid]       --lint[=fatal|invalid]   打印不能向传统unix平台移植的结构的警告
        -M                      --bignum 大数模式
        -N                      --use-lc-numeric 使用指定数字解析方式
        -n                      --non-decimal-data 无数字数据
        -o[file]                --pretty-print[=file] 输出到文件
        -O                      --optimize 使用优化
        -p[file]                --profile[=file]
        -P                      --posix  是否 posix 模式
        -r                      --re-interval
        -s                      --no-optimize 无优化
        -S                      --sandbox 沙盒模式
        -t                      --lint-old 传统 unix 警告
        -V                      --version 版本信息

To report bugs, see node `Bugs' in `gawk.info'
which is section `Reporting Problems and Bugs' in the
printed version.  This same information may be found at
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.
PLEASE do NOT try to report bugs by posting in comp.lang.awk.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

Examples:
        gawk '{ sum += $1 }; END { print sum }' file
        gawk -F: '{ print $1 }' /etc/passwd

基本命令格式 awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file 即可

2. 内置环境说明

  • 常见环境变量
变量 描述
$n 当前记录的第n个字段,字段间由FS分隔。
$0 完整的输入记录。
ARGC 命令行参数的数目。
ARGIND 命令行中当前文件的位置(从0开始算)。
ARGV 包含命令行参数的数组。
CONVFMT 数字转换格式(默认值为%.6g)
ENVIRON 环境变量关联数组。
ERRNO 最后一个系统错误的描述。
FIELDWIDTHS 字段宽度列表(用空格键分隔)。
FILENAME 当前文件名。
FNR 同NR,但相对于当前文件。
FS 字段分隔符(默认是任何空格)。
IGNORECASE 如果为真,则进行忽略大小写的匹配。
NF 当前记录中的字段数。
NR 当前记录数。
OFMT 数字的输出格式(默认值是%.6g)。
OFS 输出字段分隔符(默认值是一个空格)。
ORS 输出记录分隔符(默认值是一个换行符)。
RLENGTH 由match函数所匹配的字符串的长度。
RS 记录分隔符(默认是一个换行符)。
RSTART 由match函数所匹配的字符串的第一个位置。
SUBSEP 数组下标分隔符(默认值是\034)。
  • 常见运算符
运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|| 逻辑或
&& 逻辑与
~ ~! 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加,减
* / & 乘,除与求余
+ - ! 一元加,减和逻辑非
^ *** 求幂
++ -- 增加或减少,作为前缀或后缀
$ 字段引用
in 数组成员
  • 内部函数

内容较多,参加 awk 命令使用入门基础详解

3. 执行模式

通常使用 pattern { action } 的模式进行执行,比如 echo "AWK lines"| awk '/^AWK/ {print "这行以 AWK 开头"}'

4. 脚本编写方式

脚本与命令类似,可将多个匹配条件综合到一个执行过程里

$ cat nginx_499.awk
#!/bin/awk -f

# 标记执行过程开始
BEGIN {
    printf "BEGIN : %s \n", "start stat log...."
}

# 仅第十项参数为 200 的行执行相应 action
$10 == 200 {
    ca++
    cb++
    # 使用 next 表示后续的模式不被执行
    next
}

# 仅第十项参数为 499 的行执行相应 action
$10 == 499 {
    if ($16 > 4.99) {
        cc++
    } else if ($16 <= 4.99) {
        cd++
    }
}

# 这里无 pattern 情况下,所有行都会被执行到
{
    # 打印当前行所有内容
    print $0
    ca++
    ce++
}

# 标记执行过程结束
END {
    printf "END : %s \n", "stat result: "
    printf "total request count: %d \n",  ca
    printf "normal response count: %d \n",  cb
    printf "failed response count: %d \n",  ce
    printf "status code: 499, response time >  4.99s count: %d \n",  cc
    printf "status code: 499, response time <= 4.99s count: %d \n",  cd
}

然后执行 awk -f nginx_499.awk nginx.log 即可得到如下结果

$ awk -f nginx_499.awk nginx.log
BEGIN : start stat log....
...省略错误...
END : stat result:
total request count: 7957358
normal response count: 7897586
failed response count: 59772
status code: 499, response time >  4.99s count: 1029
status code: 499, response time <= 4.99s count: 36803

通过 chmod +x nginx_499.awk 即可使用 nginx_499.awk nginx.log 直接处理日志

5. 多行分析

内容相对比较容易解析,如下:

$ cat status.log
web01[192.168.2.100]
httpd   ok
tomcat  ok
sendmail    ok
web02[192.168.2.101]
httpd   ok
postfix ok
web03[192.168.2.102]
mysqld  ok
httpd   ok

则简单的使用变量即可实现转换,如下:

$ cat multi-line.awk
#!/bin/awk -f

# 取出当前标签
/^web/ {
    T = $0
    # 标签行处理之后,跳至下一行
    next
}
# 所有非标签行进行标签化打印即可
{
    printf "%s: \t %s \n", T, $0
}

执行 awk -f multi-line.awk status.log 即可,或者直接单行 awk '/^web/{T=$0;next;}{print T ":\t" $0;}' status.log

$ awk -f multi-line.awk status.log
web01[192.168.2.100]:    httpd  ok
web01[192.168.2.100]:    tomcat ok
web01[192.168.2.100]:    sendmail       ok
web02[192.168.2.101]:    httpd  ok
web02[192.168.2.101]:    postfix        ok
web03[192.168.2.102]:    mysqld ok
web03[192.168.2.102]:    httpd  ok

6. 常见语法

  • 变量定义
echo "hoge fuga" | \
awk '
  # 定义变量
  BEGIN {
    var = "hoge"
  }

  # 使用 match 函数匹配第一个字符
  match($1, "^" var) {
    print "match line: " var " content: " $0
  }
'

echo "hoge fuga" | \
awk '
  BEGIN {
    var="hoge"
  }
  # 使用 match 函数匹配第一个字符
  $1 ~ /^var/ {
    print "match line: " var " content: " $0
}'
  • 指定行处理
NR == 10 { print "当前为第10行, 内容是: " $0 }
  • 多条件
NR >= 10 || $NF ~ /[0-9]+/ { print "第十行之后,或者最后一个字段数据为数字的行"}
  • 常见处理
# 含有 `特殊处理` 行进行特殊处理
/特殊处理/ {
  # 判定共有 5 个字段
  if(NF == 5){
    # 有 5 个字段的行执行如下打印
    print "Number of fields: 5"
  }

  # 执行for循环操作
  for(i=0; i < 10; i++){
    # 执行十次如下打印
    printf("这是第 %02d: %2d 次循环操作。\n", i, i+1)
  }

  # 执行 while 循环操作
  while(1){
    # 死循环
    print "循环开始。"
    print "循环结束。"

    # 使用 break 跳出死循环。
    break
  }

  # 使用 next 结束处理,当前块之后的所有块都不会被执行。
  next
}

常见分析场景

1. 日志超时统计

在做 nginx 日志分析时,常会需要统计响应时长大于 某时间 请求数量统计,如下是日志:

[26/Feb/2020:14:34:52 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.170:8082 3.540 3.515 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.174:8082 2.987 2.966 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.170:8082 2.986 2.965 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.172:8082 5.983 5.959 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.172:8082 2.967 2.948 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.175:8082 3.006 2.985 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.170:8082 3.005 2.981 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:52 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 200 131 "-" 200 xxx.xxx.xxx.170:8082 0.499 0.453 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:34:59 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 200 132 "-" 200 xxx.xxx.xxx.175:8082 0.544 0.499 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:07 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 200 131 "-" 200 xxx.xxx.xxx.174:8082 0.499 0.463 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.41.228 - xxx.xxx.cn:10080 POST "POST /topics/dc_ginfo HTTP/1.1" 499 0 "-" - xxx.xxx.xxx.174:8082 2.990 2.967 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.172:8082 2.983 2.957 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.104.156 - xxx.xxx.cn:10080 POST "POST /topics/dc_ginfo HTTP/1.1" 499 0 "-" - xxx.xxx.xxx.170:8082 3.003 2.981 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.174:8082 2.981 2.957 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.175:8082 2.989 2.965 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.36.240 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.175:8082 2.992 2.972 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.171:8082 2.968 2.950 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 499 25 "-" - xxx.xxx.xxx.170:8082 2.994 2.976 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:20 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 200 130 "-" 200 xxx.xxx.xxx.174:8082 2.499 2.453 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:28 +0800] xxx.xxx.104.156 - xxx.xxx.cn:10080 POST "POST /topics/dc_ginfo HTTP/1.1" 200 106 "-" 200 xxx.xxx.xxx.171:8082 1.539 1.499 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"
[26/Feb/2020:14:35:28 +0800] xxx.xxx.34.132 - xxx.xxx.cn:10080 POST "POST /topics/dcmessage HTTP/1.1" 200 132 "-" 200 xxx.xxx.xxx.171:8082 0.499 0.460 "Mozilla/5.0 (Windows NT 5.2; rv:13.0) Gecko/20100101 Firefox/13.0.1" "-"

对状态码为 499 且响应时间 5s 的分界点数量统计:

$ awk '{if ($10 == 499 && $16 > 4.99) {ca++} else if ($10 == 499 && $16 <= 4.99) {cb++}} END{print "status 499 and resp time > 4.99: "ca
" \nstatus 499 and resp time <= 4.99: "cb}' nginx.log
status 499 and resp time > 4.99: 1
status 499 and resp time <= 4.99: 14

你可能感兴趣的:(awk 使用笔记)