• 十八、gawk进阶


    gawk支持两种变量

    1. 内建变量
    2. 自定义变量

    内建变量

    用来存放处理数据文件中的数据字段。

    如数据字段变量

    第一个数据字段变量$1表示,第二个用$2依次类推。

    字段分隔符

    模式空格或制表符

    使用-F

    常见的内建变量

    变量 描述
    FIELDWIDTHS 由空格分隔的一列数字,定义每个数据字段确定宽度
    FS 输入字段分隔符
    RS 输入记录分隔符
    OFS 输出字段分隔符
    ORS 输出记录分隔符
    ARGC 当前命令行参数个数
    ENVIRON 当前shell环境变量及其值组成的关联数组
    NF 数据文件中字段总数
    FNR 当前数据文件中的数据行数
    NR 已处理的输入记录数

    OFS默认为空格,跟FS功能一样,但是是用在print命令输出上。

    样本文件data1.txt

    [root@tzPC 22Unit]# cat data1
    data11,data12,data13,data14,data15
    data21,data22,data23,data24,data25
    data31,data32,data33,data34,data35

    FS定义以逗号分隔字符

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=","}{print $1,$2,$3}' data1
    data11 data12 data13
    data21 data22 data23
    data31 data32 data33

    OFS变量能将定义输出分隔字符

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=",";OFS="-"}{print $1,$2,$3}' data1
    data11-data12-data13
    data21-data22-data23
    data31-data32-data33

    FIELDWIDTHS变量可以不靠字段分隔符来读取记录,而使用字段宽度来计算字段。

    一旦设定FIELDWIDTHS变量就不能改了,不适用变长的字段。

    样本文件data1b

    [root@tzPC 22Unit]# cat data1b
    1005.3247596.37
    115-2.349194.00
    05810.1298100.1

    可以看到FIELDWIDTHS定义了分别以3个字符,5个字符,2个字符,5个字段长度分隔

    [root@tzPC 22Unit]# gawk 'BEGIN{FIELDWIDTHS="3 5 2 5"}{print $1,$2,$3,$4}' data1b
    100 5.324 75 96.37
    115 -2.34 91 94.00
    058 10.12 98 100.1

    RS跟ORS默认为换行符

    样本文件data2

    [root@tzPC 22Unit]# cat data2
    Riley Mullen
    123 Main Street
    Chicago, IL  60601
    (312)555-1234
    
    Frank Williams
    456 Oak Street
    Indianapolis, IN  46201
    (317)555-9876
    
    Haley Snell
    4321 Elm Street
    Detroit, MI  48201
    (313)555-4938

    FS变量设置为换行符,表示每行都是一个单独的字段

    RS设置为空字符串,表示每个空白行当作一个记录分隔符

    输出每条记录的第一个字段跟第四个字段,注意以空行分隔为一条记录,即1234行为一条记录,以 为分隔字符,即1行为一个字段,输出14字段即$1跟$4

    [root@tzPC 22Unit]# gawk 'BEGIN{FS="
    "; RS=""}{print $1,$4}' data2
    Riley Mullen (312)555-1234
    Frank Williams (317)555-9876
    Haley Snell (313)555-4938

    ARGC和ARGV变量

    这两个变量可以获取命令行参数的总数以及他们的值。

    [root@tzPC 22Unit]# gawk 'BEGIN{print ARGC,ARGV[1]}' data1
    2 data1

    ARGC表明命令行上有2个参数,分别是gawk跟data1这两个

    ARGV数组是从索引0开始,0代表命令gawk,1代表参数data1,中间的脚本不算参数

    [root@tzPC 22Unit]# gawk 'BEGIN{print ARGC,ARGV[0]}' data1
    2 gawk
    [root@tzPC 22Unit]# gawk 'BEGIN{print ARGC,ARGV[1]}' data1
    2 data1
    [root@tzPC 22Unit]# gawk 'BEGIN{print ARGC,ARGV[2]}' data1
    2 
    [root@tzPC 22Unit]# 

    ENVIRON变量

    使用关联数组来提取shell环境变量

    关联数组以文本如环境变量名HOME作为索引值

    [root@tzPC 22Unit]# gawk '
    > BEGIN{
    > print ENVIRON["HOME"]
    > print ENVIRON["PATH"]
    > }'
    /root
    /mnt/mysql/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
    [root@tzPC 22Unit]# 

    NF变量

    样本文件/etc/passwd

    [root@tzPC 22Unit]# cat /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

    FS变量设置以:分隔,OFS变量设置以:输出,NF变量为字段总数,$NF变量为最后一个数据字段的值

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=":"; OFS=":"}{print $1,NF}' /etc/passwd
    root:7
    bin:7
    daemon:7
    adm:7
    lp:7
    
    [root@tzPC 22Unit]# gawk 'BEGIN{FS=":"; OFS=":"}{print $1,$NF}' /etc/passwd
    root:/bin/bash
    bin:/sbin/nologin
    daemon:/sbin/nologin
    adm:/sbin/nologin
    lp:/sbin/nologin

    FNR变量

    样本文件data1

    [root@tzPC 22Unit]# cat data1
    data11,data12,data13,data14,data15
    data21,data22,data23,data24,data25
    data31,data32,data33,data34,data35
    [root@tzPC 22Unit]# 

    gawk命令行定义了两个输入文件data1,脚本会打印第一个数据字段的值和FNR变量的当前值,gawk程序处理第二个数据文件时,FNR值归1

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=","}{print $1,"FNR="FNR}' data1 data1
    data11 FNR=1
    data21 FNR=2
    data31 FNR=3
    data11 FNR=1
    data21 FNR=2
    data31 FNR=3

    NR变量

    还是data1样本文件

    gawk程序在处理第二个数据文件时,NR值继续没有归1而是继续计数

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=","}{print $1,"FNR="FNR,"NR="NR}' data1 data1
    data11 FNR=1 NR=1
    data21 FNR=2 NR=2
    data31 FNR=3 NR=3
    data11 FNR=1 NR=4
    data21 FNR=2 NR=5
    data31 FNR=3 NR=6

    自定义变量

    变量命名规则

    任意长度的字母、数字、下划线

    不能以数字开头

    区分大小写

    在脚本中给变量赋值

    [root@tzPC 22Unit]# gawk '
    > BEGIN{
    > testing="This is a test"
    > print testing
    > testing=45
    > print testing
    > }'
    This is a test
    45

    使用算数运算

    [root@tzPC 22Unit]# awk 'BEGIN{x=4; x=x*2+3; print x}'
    11

    在命令行上给变量赋值

    输出data1每行第三个字段

    [root@tzPC 22Unit]# cat script1 
    BEGIN{FS=","}
    {print $n}
    [root@tzPC 22Unit]# gawk -f script1 n=3 data1
    data13
    data23
    data33

    要让变量在BEGIN中使用需要在gawk后接-v选项,注意-v必须放在脚本代码前

    [root@tzPC 22Unit]# cat script2
    BEGIN{print "The starting value is " n; FS=","}
    {print $n}
    [root@tzPC 22Unit]# gawk -v n=3 -f script2 data1
    The starting value is 3
    data13
    data23
    data33

    定义数组

     gawk编程语言使用关联数组,即使用字符串作为数组的索引值。

    语法

    var[index] = element

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

    [root@tzPC 22Unit]# gawk 'BEGIN{
    > capital["Illinois"] = "Springfield"
    > print capital["Illinois"]
    > }'
    Springfield

    算数运算

    [root@tzPC 22Unit]# gawk 'BEGIN{
    > var[1] = 34
    > var[2] = 3
    > total = var[1] + var[2]
    > print total
    > }'
    37

    遍历数组

    使用for循环

    这里需要注意的是,test存储的是索引值,var是变量名

    索引值输出是无序的,以agmn定义,并不会以agmn顺序输出

    [root@tzPC 22Unit]# gawk 'BEGIN{
    > var["a"] = 1
    > var["g"] = 2
    > var["m"] = 3
    > var["n"] = 4
    > for (test in var)
    > {
    >   print "Index:",test,"  Value:",var[test]
    > }
    > }'
    Index: m   Value: 3
    Index: n   Value: 4
    Index: a   Value: 1
    Index: g   Value: 2

    删除数组变量

    这里有个有趣的地方,这里for 可以不写do-done跟{},写在一行跟换行写都能执行成功

    [root@tzPC 22Unit]# gawk 'BEGIN{
    var["a"] = 1
    var["g"] = 2
    for (test in var)
    {
      print "Index:",test,"  Value:",var[test]
    }
    delete var["g"]
    print "数组键值g已删除"
    for (test in var)
      print "Index:",test,"  Value:",var[test]
    }'
    Index: a Value: 1 Index: g Value: 2 数组键值g已删除 Index: a Value: 1

    正则表达式

    正则表达式必须出现在它要控制的程序脚本前

    样本文件

    [root@tzPC 22Unit]# cat data1
    data11,data12,data13,data14,data15
    data21,data22,data23,data24,data25
    data31,data32,data33,data34,data35
    [root@tzPC 22Unit]# 

    如/11/正则表达式写在脚本前

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=","} /11/{print $1}' data1
    data11

    匹配操作符~

     匹配操作符可以将正则表达式使用在特定的数据字段上。

    $1表示第一个数据字段,此表达式会匹配第一个字段是以data开头的所有记录

    $1 ~ /^data/

    该脚本会匹配第二个字段是以data2开头的并打印出此行

    [root@tzPC 22Unit]# gawk 'BEGIN{FS=","} $2 ~ /^data2/{print $0}' data1
    data21,data22,data23,data24,data25

    以:作为分隔符,第一个字段是以root开头的行,输出第一个字段跟最后一个字段

    [root@tzPC 22Unit]# gawk -F: '$1 ~ /root/{print $1,$NF}' /etc/passwd
    root /bin/bash

    可以使用!排除正则表达式的匹配

    [root@tzPC 22Unit]# gawk -F: '$1 !~ /root/{print $1,$NF}' /etc/passwd
    bin /sbin/nologin
    daemon /sbin/nologin
    adm /sbin/nologin
    lp /sbin/nologin
    ...

    使用数学表达式

    显示第四个字段即组ID为0的用户

    [root@tzPC 22Unit]# gawk -F: '$4 == 0{print $1}' /etc/passwd
    root
    sync
    shutdown
    halt
    operator

    还能使用比较表达式

    ==、<=、<、>=、>等

    [root@tzPC 22Unit]# gawk -F, '$1 == "data11" {print $1}' data1
    data11

    使用结构化命令if

     语法格式

    if (condition)
        statement1
    #或者
    if (condition) statement1

    样本文件data4

    [root@tzPC 22Unit]# cat data4
    23
    123
    4
    45
    56
    7
    23

    找出大于20的第一个字段

    [root@tzPC 22Unit]# gawk '{if ($1 > 20) print $1}' data4
    23
    123
    45
    56
    23

    如果要在if语句中使用多条命令需要使用{}

    [root@tzPC 22Unit]# gawk '{
    > if ($1 >20)
    > {
    >   x= $1 * 2
    >   print x
    > }
    > }' data4
    46
    246
    90
    112
    46

    if-else语句

    [root@tzPC 22Unit]# gawk '{
    > if ($1 > 20)
    > {
    >   x= $1 * 2
    >   print x
    > } else
    > {
    >   x= $1 /2
    >   print x
    > }}' data4
    46
    246
    2
    90
    112
    3.5
    46

    如果单行写,if语句部分需要加分号

    [root@tzPC 22Unit]# gawk '{if ($1 > 20) print $1 * 2; else print $1 / 2 }' data4
    46
    246
    2
    90
    112
    3.5
    46

    while语句

    样本文件data5

    [root@tzPC 22Unit]# cat data5
    155 158 121
    121 154 165
    188 164 125

    计算每行平均值

    [root@tzPC 22Unit]# gawk '{
    > total = 0
    > i = 1
    > while (i < 4)
    > {
    >   total += $i
    >   i++
    > }
    > avg = total /3
    > print "Average:",avg
    > }' data5
    Average: 144.667
    Average: 146.667
    Average: 159

    可以使用break跟continue语句

    计算每行前两个数的平均值

    [root@tzPC 22Unit]# gawk '{
    > total = 0
    > i = 1
    > while (i < 4)
    > {
    >   total += $i
    >   if (i == 2)
    >     break
    >     i++
    > }
    > avg = total /2
    > print "The average of the first two data elements is: ",avg
    > }' data5
    The average of the first two data elements is:  156.5
    The average of the first two data elements is:  137.5
    The average of the first two data elements is:  176

    average平均,elements元素

    do-while语句

    类似while语句,但会在检查条件之前执行命令。

    该语句保证在检查条件之前至少先执行一次命令。

    读取样本文件data5中每行的每个字段并将它累加到一起,直到>=150后输出

    [root@tzPC 22Unit]# gawk '{
    > total = 0
    > i = 1
    > do
    > {
    >   total += $i
    >   i++
    > } while (total <150)
    > print total }' data5
    155
    275
    188

    for语句

    gawk编程语言支持C风格的for循环

     同样计算data5每行平均值

    [root@tzPC 22Unit]# gawk '{
    > total = 0
    > for (i = 1; i < 4; i++)
    > {
    >   total += $i
    > }
    > avg = total /3
    > print "Average:",avg
    > }' data5
    Average: 144.667
    Average: 146.667
    Average: 159

    格式化打印printf命令

    语法格式

    print "format string", var1, var2 ...

    format string格式化指定符,指定变量如何显示。

    第一个format string对应第一个变量,依次类推

    格式化指定符控制字母

    控制字母 描述 控制字母 描述
    c 将一个数作为ASCII字符显示 g 用科学计数法或浮点数显示
    d 显示一个整数 o 显示一个八进制数
    i 显示一个整数 s 显示一个文本字符串
    e 用科学计数法显示一个数 x 显示一个十六进制数
    f 显示一个浮点数 X 显示一个十六进制,但用大写字母A~F

    注意使用控制字母前需要加上%

    用科学计数法显示一个很大的数值

    [root@tzPC 22Unit]# gawk 'BEGIN{
    > x = 10 * 100
    > printf "The answer is: %e
    ",x
    > }'
    The answer is: 1.000000e+03

    出了控制字母,还有3种修饰符

    • width:只当输出字段长度,如果小于这个值,printf会将文本右对齐并以空格填充,如果大于这个值,则按实际长度输出。
    • prec:指定小数点后几位
    • -:采用左对齐

    样本文件data2

    [root@tzPC 22Unit]# cat data2
    Riley Mullen
    123 Main Street
    Chicago, IL  60601
    (312)555-1234
    
    Frank Williams
    456 Oak Street
    Indianapolis, IN  46201
    (317)555-9876
    
    Haley Snell
    4321 Elm Street
    Detroit, MI  48201
    (313)555-4938

    使用print输出

    [root@tzPC 22Unit]# gawk 'BEGIN{FS="
    "; RS=""}{print $1,$4}' data2
    Riley Mullen (312)555-1234
    Frank Williams (317)555-9876
    Haley Snell (313)555-4938

    使用printf输出

    [root@tzPC 22Unit]# gawk 'BEGIN{FS="
    "; RS=""}{printf "%s %s
    ", $1, $4}' data2
    Riley Mullen (312)555-1234
    Frank Williams (317)555-9876
    Haley Snell (313)555-4938

    你会发现没有差别,是不是很惊喜!哈哈!

    指定每行第一个字段输出宽度为16个字符,默认是右对齐

    [root@tzPC 22Unit]# gawk 'BEGIN{FS="
    "; RS=""}{printf "%16s %s
    ", $1, $4}' data2
        Riley Mullen (312)555-1234
      Frank Williams (317)555-9876
         Haley Snell (313)555-4938

    加-变成左对齐

    [root@tzPC 22Unit]# gawk 'BEGIN{FS="
    "; RS=""}{printf "%-16s %s
    ", $1, $4}' data2
    Riley Mullen     (312)555-1234
    Frank Williams   (317)555-9876
    Haley Snell      (313)555-4938

    使用%15.2f格式指定printf输出将浮点值近似到小数点后两位,15是宽度值

    [root@tzPC 22Unit]# gawk '{
    total = 0
    for (i = 1; i < 4; i++)
    {
      total += $i
    }
    avg = total /3
    printf "Average: %15.2f
    ",avg
    }' data5
    Average:          144.67
    Average:          146.67
    Average:          159.00

    内建函数

     gawk编程语言提供了不少内置函数,加快编码效率。

    数学函数

    gawk数学函数

    函数 描述 函数 描述
    atan2(x,y) x/y的反正切 rand() 取大于0小于1的随机浮点值
    cos(x) x的余弦 sin(x) x的正弦
    int(x) x的整数部分 sqrt(x) x的平方根
    log(x) x的自然对数 srand(x) 为计算随机数指定一个初始值

    看到这几个算数符有没有回到初中的感觉哈哈。

     int()相当于转整型,值为5.6时取5,不会四舍五入

    rand()比较常用,取随机数。

    返回0~9的随机数

    x = int(10 * rand())

    gawk语言对处理的数值有确定范围,如果数值过大会报错

    [root@tzPC 22Unit]# gawk 'BEGIN{x=exp(1000);print x}'
    gawk: cmd. line:1: warning: exp: argument 1000 is out of range
    inf
    [root@tzPC 22Unit]#

    gawk还支持按位操作数据的函数,对处理二进制值很有用,我目前暂时不需要,在书P488

    字符串函数

     书P488有个表,太多了,写几个常用的就行了

    小写转大写

    toupper(s)

    [root@tzPC 22Unit]# gawk 'BEGIN{x = "testing"; print toupper(x);print length(x)}'
    TESTING
    7

    asort(s,d)

    将数组s按数据元素值排序,排序后的数组会储存在数组d中

    [root@tzPC 22Unit]# gawk 'BEGIN{
    > var["a"] = 1
    > var["b"] = 2
    > var["c"] = 3
    > var["d"] = 4
    > asort(var, test)
    > for (i in test)
    >   print "Index:",i," value:",test[i]
    > }'
    Index: 4  value: 4
    Index: 1  value: 1
    Index: 2  value: 2
    Index: 3  value: 3

    可以看到,test的索引值跟数据元素都已经变成数组var排序后的数据元素值了,且asort是按照ascii码排序的。

    asorti(s,d)

    将数组s按索引排序,排序后的数组会储存在数组d中

     split(s, a [r])

    将s使用FS字符或正则表达式r(可选)处理后分开放到数组a中

    将data1中的每行使用逗号分割,放入数组var中,打印索引1跟5中的元素

    [root@tzPC 22Unit]# gawk 'BEGIN{ FS=","}{
    > split($0,var)
    > print var[1], var[5]
    > }' data1
    data11 data15
    data21 data25
    data31 data35

    时间函数

    gawk的时间函数

    函数 描述
    mktime(datespec) 将YYYY MM DD HH MM SS格式指定的日期转换成时间戳
    strftime(format timestamp)  将当前时间戳或timestamp(可选)转换成格式化日期
    systime() 返回当前时间戳
    [root@tzPC 22Unit]# gawk 'BEGIN{
    > date = systime()
    > day = strftime("%A, %B %D, %Y", date)
    > print day
    > }'
    Saturday, September 09/19/20, 2020
    [root@tzPC 22Unit]# gawk 'BEGIN{
    date = systime()
    day = strftime("%A, %B %d, %Y", date)
    print day
    }'
    Saturday, September 19, 2020

    自定义函数

    语法格式

    function name(variables)
    {
        statements
       return value #返回值 }

    将返回值赋值给变量

    x = myrand(100)

    函数必须定义在所有代码块之前(包括BEGIN代码块)

    [root@tzPC 22Unit]# gawk '
    function myprint()
    {
      printf "%-16s  %s
    ", $1, $4
    }
    BEGIN{FS="
    "; RS=""}
    {
      myprint()
    }' data2
    Riley Mullen      (312)555-1234
    Frank Williams    (317)555-9876
    Haley Snell       (313)555-4938

    使用函数库

     总所周知,函数库相当于类。

    先创建gawk函数文件,也就是相当于java类

    [root@tzPC 22Unit]# cat funclib
    function myprint()
    {
      printf "%-16s  %s
    ", $1, $4
    }
    function printthird()
    {
      print $3
    }
    function myrand(limit)
    {
      return int(limit * rand())
    }

    创建脚本文件

    [root@tzPC 22Unit]# cat script4
    BEGIN{ FS="
    "; RS=""}
    {
      myprint()
    }

    在命令行上使用-f指定函数库文件以及脚本文件

    [root@tzPC 22Unit]# gawk -f funclib -f script4 data2
    Riley Mullen      (312)555-1234
    Frank Williams    (317)555-9876
    Haley Snell       (313)555-4938

    学习来自:《Linux命令行与Shell脚本大全 第3版》第22章

    今天的学习是为了以后的工作更加的轻松!
  • 相关阅读:
    简洁又漂亮的单网页404页源码(html格式404源码)
    运行bee run之后出现的错误以及解决方法
    window beego 安装出现的错误
    golang gin框架 使用swagger生成api文档
    go语言切片作为函数参数
    Go中函数接收器不能改变接收者的地址
    docker 删除none镜像
    redis下载安装
    git切换分支
    angular自定义验证器添加入模板驱动表单
  • 原文地址:https://www.cnblogs.com/tz90/p/13611754.html
Copyright © 2020-2023  润新知