欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

gawk进阶

发布时间:2023/12/20 73 豆豆
生活随笔 收集整理的这篇文章主要介绍了 gawk进阶 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

如果对 gawk 不了解, 先阅读 初识gawk 这篇博客.

1 使用变量

gawk 编程语言支持两种不同类型的变量:

  • 内建变量
  • 自定义变量
  • 1.1 内建变量(built-in variables)

    查看 gawk 的所有内建变量, 可以通过 man gawk 然后搜索 Built-in Variables.

    这里列举一些常用的内建变量:

    变量描述
    FIELDWIDTHS由空格分隔的一列数字, 定义了每个数据字段的确切宽度(field widths)
    FS输入字段分隔符(input field separator, by default a space)
    RS输入记录分隔符(input record separator, by default a newline)
    OFS输出字段分隔符(output field separator, by default a space)
    ORS输出记录分隔符(output record separator, by default a newline)
    ARGC当前命令行参数个数(argument count)
    ARGV当前命令行参数数组(argument values)
    FNR当前文件的记录数(第几行)(The input record number in the current input file)
    NF当前记录的字段数(The number of fields in the current input record)
    ENVIRON由 shell 环境变量名和值组成的关联数组(如, ENVIRON[“HOME”] 就是 shell 中的 $HOME)

    gawk 命令行参数 -F 和 内建变量 FS 的效果是一样的.
    由 FS 分隔出来的 数据字段(用$1, $2等表示), $n 变量也属于内建变量.

    看个例子帮助理解 FS 和 OFS:

    $ cat test.txt 11,12,13,14,15 21,22,23,24,25 31,32,33,34,35$ gawk 'BEGIN {FS=","} {print $1,$2,$3}' test.txt 11 12 13 21 22 23 31 32 33$ gawk 'BEGIN {FS=","; OFS="---"} {print $1,$2,$3}' test.txt 11---12---13 21---22---23 31---32---33

    FIELDWIDTHS 只适用于固定长度的字符串, 如果设置了 FIELDWIDTHS, gawk 会忽略 FS 变量, 并根据提供的 字段宽度 计算字段.
    示例:

    $ cat test.txt 1002.0301 1123.4007 6665.1239$ gawk 'BEGIN {FIELDWIDTHS="3 5 1"} {print $1, $2, $3}' test.txt 100 2.030 1 112 3.400 7 666 5.123 9

    使用 RS 示例:

    $ cat test.txt miyan xiao 木叶村 3组33号 15556928888rosie cui 魔都 上海中心100层 18806166000$ gawk 'BEGIN {FS="\n"; RS=""} {print $1, $3}' test.txt miyan xiao 15556928888 rosie cui 18806166000

    上面的数据比较特殊, 一组数据分散在多行(第1行是姓名, 第2行是地址, 第3行是电话; 不同组用空行分隔).
    要想把姓名和电话在一行输出, 可以用 换行符\n 当做 FS, 用 空行"" 当做 RS.

    NF 表示 一个输入记录(input record, 默认是一行) 的字段个数, 我们可以用 $NF 获取到最后一个字段:

    $ gawk 'BEGIN {FS=":"; OFS=":"} {print $1, $NF}' /etc/passwd root:/bin/bash bin:/sbin/nologin daemon:/sbin/nologin adm:/sbin/nologin ...

    1.2 自定义变量

    gawk 自定义的变量名可以是 字母, 数字 和 下划线, 但不能以 数字 开头.
    gawk 变量区分大小写.

    gawk 赋值语句 不要求 = 左右没有空格(shell 要求).
    示例:

    $ gawk 'BEGIN { test = "this is a test"; print test }' this is a test$ gawk 'BEGIN { test = "this is a test"; print test; quote> test = 45; print test }' this is a test 45$ gawk 'BEGIN { test = "this is a test"; print test; quote> test = 45; print test; quote> test = test * 2 + 1; print test}' this is a test 45 91

    和 shell 脚本一样, gawk 变量不用指定数据类型, 一个变量既可以赋值 字符串 也可以赋值 数值.
    gawk 支持处理 数值 的标准操作符, 包括取余(%)和幂运算(^或**).

    2 处理数组

    关联数组数字数组 不同之处在于它的 索引值 可以是任意文本字符串.
    关联数组 更像是 散列表 或 字典.
    gawk 中的数组是 关联数组.

    2.1 定义数组变量

    格式:

    var[index] = element

    var 是变量名, index 是索引值, element 是元素值.

    示例:

    $ gawk 'BEGIN { quote> names["mx"] = "miyan xiao" quote> print names["mx"] quote> }' miyan xiao

    2.2 遍历数组变量

    可以使用 gawk 提供的 for-in 语句遍历数组, 格式如下:

    for (var in array) {statements )

    示例:

    $ gawk 'BEGIN{ quote> vars["a"]=1 quote> vars["b"]=2 quote> for (i in vars){ quote> print "index:", i, " - value:", vars[i] quote> } quote> }' index: a - value: 1 index: b - value: 2

    扩展:
    可以使用 delete vars["a"] 删除数组元素.

    3 使用模式

    gawk 支持多种类型的 匹配模式 来过滤数据记录.

    3.1 正则表达式

    在使用正则时, 正则必须出现在 它要控制的程序脚本的 左花括号({) 前.

    正则匹配示例:

    $ cat test.txt 11,12,13 21,22,23 31,32,33$ gawk 'BEGIN {FS=","} /11/{print $0}' test.txt 11,12,13

    解释:
    上面的 正则表达式 /11/ 是针对一条记录(一行)做匹配的.

    3.2 匹配操作符

    匹配操作符(matching operator, 符号~) 可以指定 正则表达式 匹配指定的 数据字段变量($n).
    比如: $1 ~ /^data/ 表示 过滤出第一个字段($1) 以文本 data 开头(/^data/)的所有记录.

    ~ 让正则表达式的对记录的匹配更细粒度了(从一个记录匹配到一个字段匹配).

    ~ 匹配字段 示例:

    $ cat test.txt 11,12,13 21,22,23 31,32,33$ gawk 'BEGIN {FS=","} $3 ~ /23$/{print $0}' test.txt 21,22,23

    表达式 $3 ~ /23$/ 可以匹配出 第三个字段($3) 以 23 结尾(23$)的所有记录.

    再看一例:

    $ gawk -F: '$1 ~ /miyan/{print $1,$NF}' /etc/passwd miyan /bin/zsh

    扩展:
    可以使用 ! 来排除正则表达式的匹配.
    比如: $1 !~ /re/ 表示 如果记录没有匹配上正则 re, 程序脚本就会作用到该记录.

    3.3 数学表达式

    除了正则, 也可以在 匹配模式 中使用 数学表达式.
    可以使用的数学表达式:==, <=,<,>=,>.

    显示 所有属于root用户组(组ID为0) 的系统用户:

    t$ gawk -F: '$4 == 0 {print $1}' /etc/passwd root sync shutdown halt operator

    4 结构化命令

    gawk 的结构化/控制 语句 和 Java 很类似, 这里从略.

    4.1 if

    4.2 while

    4.3 do-while

    4.4 for

    5 格式化打印

    print 命令在控制显示数据的格式上能力有限.
    gawk 提供了 printf 格式化打印命令(accept the conversion specification formats).
    printf 命令的格式:

    printf "format_string", var1, var2 ...

    format_string 采用如下格式:
    %[modifier]control_letter

    control_letter 是控制字符, 控制字符 列表:

    控制字母描述
    c将一个数作为ASCII字符显示(A single character.)
    d 和 i显示一个整数值(A decimal number, the integer part)
    e用科学计数法显示一个数(A floating point number of the form [-]d.dddddde[±]dd.)
    g科学计数法显示, 相对于 e 更短(nonsignificant zeros suppressed)
    f显示一个浮点值(A floating point number of the form [-]ddd.dddddd.)
    o显示一个八进制值(An unsigned octal number)
    s显示一个字符串(A character string.)
    x显示一个十六进制值(An unsigned hexadecimal number)
    X显示一个十六进制值, 使用 ABCDEF 而不是 abcdef

    除了控制字母 外, 还有 3 种 修饰符(modifier) 可以进一步控制输出:

  • width: 指定 输出字段最小宽度 的数字值. 如果输出短于这个值, 用空格对齐; 如果长于这个值, 原样输出.
  • prec: precision 是一个数字值, 指定 浮点数小数点后的位数, 或者 字符串显示的最大字符数.
  • -(减号): 采用左对齐而不是右对齐.
  • 结合 控制字符 和 修饰符, 可以得到 format_string 的完整格式如下:

    %[-][width][.prec]control_letter

    示例:

    $ gawk 'BEGIN{ printf "%s %s\n", "hello", "wold"}' hello wold

    注意: printf 不会自动添加换行, 上面我们手动添加了 \n 来换行.

    再看一例:

    $ gawk 'BEGIN{ printf "%-6.5s===%15s===%.3s \n", "123456789", "123456789", "123456789"}' 12345 === 123456789===123

    上面打印 3 个一样的字符串(从1到9共9个字符);

    • %-6.5s 表示采用 左对齐(-), 字符串宽度(width)为6, 保留5个字符(prevision为5). 因为只有5个字符而宽度是6, 所以 12345 后面补充了一个 空格.
    • %15s 表示采用默认的右对齐, 字符串宽度(width)为15, 123456789 前面补充了6个空格.
    • %.3s 表示保留3个字符(prevision为3).

    6 内建函数

    gawk 支持一些常见的数学函数, 字符串函数, 时间函数.

    数学函数如下:
    指数函数, 自然对数, 平方根, 随机数等等, 这里不做介绍.

    6.1 字符串函数

    gawk 支持的字符串处理函数如下(部分):

    函数描述
    asort(s [,d])将数组s 按数据 元素值排序. 索引值会被替换成新的排序顺序的连续数字. 若指定了d, 则排序后的数组会被存储在数组d 中
    asorti(s [,d])将数组s 按数据 索引值排序. 生成的数组会将索引值作为元素值, 用连续的数字索引来表明排序数学. 若指定了d, 则排序后的数组会被存储在数组d 中
    index(s, t)返回字符串t 在字符串s 中的索引值, 没找到返回0
    length([s])返回字符串s 的长度, 没有指定字符串则返回 $0 的长度
    match(s, r [,a])返回字符串s 中 正则表达式r 出现的位置的索引. 如果指定了数组a, 它会存储正则匹配到的那部分.
    split(s, a [, r])将s 用 FS 或正则r 分开放到数组 a 中, 返回字段的总和.
    sprintf(format, variables)参见上一节
    sub(r, s [, t])在变量$0 或 目标字符串t 中 查找正则r 的匹配. 如果找到了, 就用字符串s 替换掉第一处匹配
    substr(s, i [, n])返回 s 中从索引值i 开始的 n个字符组成的子串. 如果未提供n, 则返回s 剩下的部分
    tolower(s)s转小写
    toupper(s)s转大写

    示例:

    timeout 60 tail -f access.log | \awk '{c[substr($9, 1,1) "xx"]++; printf("\r2xx:%d 3xx:%d 4xx:%d 5xx:%d", c["2xx"],c["3xx"],c["4xx"],c["5xx"])}'

    access.log 是一个接口访问的日志文件, 可以用上面的命令 监控60秒接口访问返回的情况(有多少个2xx, 3xx, 4xx, 5xx http 状态码).
    状态码(2xx等) 放入关联数组 c[] 中存储.

    access.log 的一条示例:

    192.168.0.2 - - [08/Sep/2021:00:00:01 +0000] "GET /api/v1/about HTTP/1.0" 200 201 "-" "-" 2

    6.2 时间函数

    gawk 支持的时间函数:

    函数描述
    mktime(dataspec)将一个按 YYYY MM DD HH MM SS 格式指定的日期换成时间戳
    strftime(format [, timestamp])将当前时间的时间戳 或 指定的时间戳timestamp 转化为格式化日期
    systime()当前时间的时间戳

    总结

    以上是生活随笔为你收集整理的gawk进阶的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。