zoukankan      html  css  js  c++  java
  • awk 实用案例介绍

     

    awk 简介

    • awk是 3 个姓氏的首字母,代表该语言的 3 个作者
    • awk的版本有很多,包括: 旧版 awk,新版 awk(nawk), GNUawk(gawk)等
    • awk程序有 awk命令、括在引号或写在文件中的指令以及输入文件这几个部分组成

    从文件输入

    • 格式:
    –gawk '/匹配字符串/' 文件名
    –gawk '{处理动作}' 文件名
    –gawk '/匹配字符串/ {处理动作}' 文件名
    实例:
    [root@desktop243 Desktop]# gawk -F: '/student/{print $3}' /etc/passwd
    500
    #-F:以":"号为分隔符分割出参数
    [root@desktop243 Desktop]# gawk -F: '/student/{print $1,$3}' /etc/passwd
    student 500
    [root@desktop243 Desktop]# gawk -F: '/student/{print $0}' /etc/passwd
    student:x:500:500::/home/student:/bin/bash

    awk 工作原理

    以下面的内容的 names 文件名举例按步骤解析 awk 的处理过程
    [root@desktop243 Desktop]# vim names
    Tome Savage 100
    Molly Lee 200
    John Doe 300
    编辑这个 names文件时,Tome 行是多个出来空格,Molly 行是一个出来空格,John 是空格键打出来的空格。使用下面 awk命令处理
    cut 无法识别空格键和<Tab>打出来的空格
    [root@desktop243 Desktop]# cat names | cut -d ' ' -f 1
    Tome
    Molly Lee
    John
    [root@desktop243 Desktop]# cat names | cut -d ' ' -f 2
    Savage
    Doe
    gawk能区分空格键和<Tab>打出来的空格,“,”是代表打印时$1 和$3 之间有空格
    [root@desktop243 Desktop]# gawk '{ print $1,$3}' names
    Tome 100
    Molly 200
    John 300
    第一步:awk对文件或管道的内容一次只处理一行,将获取到
    的这一行赋给内部变量 $0
    第二步:这一行的内容按 awk内部变量 FS 定义的分隔符,缺省为空格(包括 tab 制表符)分解成字段,每一段存储在从 $1 开始的变量中
    第三步:awk中 print 命令打印字段
    –{print $1,$3} #只取有用的第一段和第三段
    –在打印时$1 和$3 之间由空格间隔。
    ","逗号是一个映射到内部的输出字段分隔符(OFS),OFS 变量缺省为空格,逗号在输出时被空
    格替换
    Tome 100
    Molly 200
    John 300
    • 接下来,awk处理下一行数据,直到所有的行处理完
    实例:
    OFS,输出字段分隔符定义为两个制表符,“,”在输出时被制表符替换
    [root@desktop243 Desktop]# gawk '{ OFS="		";print $1,$3}' names
    Tome 100
    Molly 200
    John 300

    从命令输入

    • awk还可以处理通过管道接收到的 Linux 命令的结果,shell程序通常使用 awk 做深处理
    • 格式:
    –命令 | gawk '/匹配字符串/'
    –命令 | gawk '{处理动作}'
    –命令 | gawk '/匹配字符串/ {处理动作}'
    df | gawk '$4 > 200000' #剩余空间大于 200000 的磁盘
    [root@desktop243 Desktop]# df | gawk '$3 > 100'
    Filesystem 1K-blocks Used AvailableUse% Mounted on
    16126920 2940932 12366788 20% /
    tmpfs 477200 260 476940 1% /dev/shm
    /dev/sda1 99150 58800 35230 63% /boot
    516040 21940 467888 5% /home

    格式化输出 print 函数

    awk命令操作处理部分是放在 "{}"(括号)中
    print 函数将变量和字符夹杂着输出,如同 linux 中的 echo 命令
    [root@desktop243 Desktop]# date
    Sat Oct 15 16:15:18 CST 2011
    [root@desktop243 Desktop]# date | gawk '{print "Month: "$2"
    Year:",$6}'
    Month: Oct
    Year: 2011
    注意上面的例子,一种是直接在Month空格后连接$2,另一种是在Year和$6 之间使用了逗号,都由 OFS 决定

    OFMT 变量

    在 OFMT 中定义数字的格式
    模拟分区大小的转换,保留小数点后 2 位:
    [root@desktop243Desktop]#echo -e "/dev/sda1	1234325
    /dev/sda3	2209"
    > | gawk '{OFMT="%.2f";print $1":",$2/1024,"M"}'
    /dev/sda1: 1205.40 M
    /dev/sda3: 2.16 M
    #$2/1024 前后必须要有","作为分隔定义,如果没有其中一个就会不能实现打印小数点后 2
    默认为"%.6gd",只会打印 6 位
    [root@desktop243Desktop]#echo -e "/dev/sda1 1234325 /dev/sda3 2209"
    |gawk '{prrnt $1":",$2/1024,"M"}'
    /dev/sda1: 1205.4 M
    /dev/sda3: 2.15723 M

    printf 函数转义字符

    printf 与 C 语言中的 printf 雷同
    –转义字符
    [root@desktop243 Desktop]# cat names
    Tome Savage 100
    Molly Lee 200
    John Doe 300
    names 文件中第 2 列的第一个字符:-%c 字符
    [root@desktop243 Desktop]# gawk '{printf("The charcter is %c
    ",$2)}' names
    The charcter is S
    The charcter is L
    The charcter is D
    names 文件中第 2 列的字符串:–%s 字符串
    [root@desktop243 Desktop]# gawk '{printf("The string is %s
    ",$2)}' names
    The string is Savage
    The string is Lee
    The string is Doe
    打印一个人的名字和年龄:–%d 十进制整数
    规定好了是字符串或者整数,后面的变量就必须是与之匹配的类型,否则会出错。
    [root@desktop243 Desktop]# echo "yangwawa 10"|gawk 
    > '{printf("%s is %d years old.
    ",$1,$2)}'
    yangwawa is 10 years old.
    –%f 浮点数
    [root@desktop243 Desktop]# echo "yangwawa 10 155"|gawk
    > '{printf("%s is %d years old,his heigth si %.2fm.
    ",$1,$2,$3/100)}'
    yangwawa is 10 years old,his heigth si 1.55m.

    printf 函数修饰符

    打印时需要对齐,下面提供一些打印输出时所用到的修饰符
    -(横杠) 左对齐和右对齐(默认),加| |是为了突出长度和对齐效果:
    [root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to 
    > |%s| lab
    ",$1)}'
    Welcome to |Bluefox|lab
    [root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to
    > |%10s|lab
    ",$1)}'
    Welcome to | Bluefox|lab
    [root@desktop243 Desktop]# echo "Bluefox" | gawk '{printf("Welcome to
    > |%-10s|lab
    ",$1)}'
    Welcome to |Bluefox |lab
    #(井号) 显示 8 进制时前面加 0,显示 16 进制时加 0x
    +(加号) 显示正负值时的正+负-号
    0(零) 用 0 对显示值填充空白处
    练习:将文件(之前很乱的)names整理并保存,要求每一行每一列都要对齐:
    [root@desktop243 Desktop]# gawk '{printf("%s		%s		%d
    ",$1,$2,$3)}' 
    >names > name ;rm -f names ;mv name names
    [root@desktop243 Desktop]# cat names
    Tome Savage 100
    Molly Lee 200
    John Doe 300

    文件中的 awk 命令

    • 将 awk写入一个文件中,更适合复杂的程序
    • 使用 -f 选项指定 awk的文件名
    • awk一次读取一条记录,测试文件中的每一条命令这样循环
    根据下面显示结果分析代码:
    执行结果:
    [root@desktop243 Desktop]# cat names | gawk -f abc.awk
    ________--------________
    Nice to meet you -->Molly
    ________--------________
    ________--------________
    John
    代码:
    [root@desktop243 Desktop]# cat abc.awk
    #!/bin/gawk
    /^[Mm]olly/{print "Nice to meet you -->"$1}
    {print "________--------________"}
    $3>200 {print $1}
    被测试的文件:
    [root@desktop243 Desktop]# cat names
    Tome Savage 100
    Molly Lee 200
    John Doe 300
    分析:
    程序开始后首先读到的$0 是 Tome Savage 100,开始的字符既不是 M 也不是m, 后 面 的 {print "Nice to meet you -->"$1}不 会 执 行 , 执 行 {print "________
    --------________"}后,判断 100 不大于 200,则 {print $1}不执行;接着$0 是 Molly
    Lee 200,首字符串匹配,执行{print "Nice to meet you -->"$1}的结果是
    Nice to meet you -->Molly,然后执行下一句,执行最后一句时发现 200 不大于 200,
    {print $1}不执行;最后传给$0的是John Doe 300,第一句由于不匹配而没有
    执行,执行完第二句代码,最后 300 大于 200,所以执行{print $1},结果是显示 John。
    小小地修改一下代码:
    #!/bin/gawk
    /^[Mm]olly/{print "Nice to meet you -->"$1;
    print "________--------________"}
    $3>200 {print $1}
    再测试,结果:
    [root@desktop243 Desktop]# gawk -f abc.awk names
    Nice to meet you -->Molly
    ________--------________
    John

    记录与字段

    记录分隔符:默认行输入和输出的分隔符都是回车 ,保存在 RS 和 ORS 内部变量中
    实例:
    默认:
    [root@desktop243 Desktop]# gawk '{print $1,$2}' names
    Tome Savage
    Molly Lee
    John Doe
    自定义:
    [root@desktop243 Desktop]# gawk 'ORS="
    +-+
    "{print $1,$2}' names
    Tome Savage
    +-+
    Molly Lee
    +-+
    John Doe
    +-+
    变量$0: awk每次一行取得整条记录,$0 随之改变,同时内部变量 NF(字段的总数,即列数)也随之变化
    实例:添加一个只有 2 列的数据,测试 NF:
    [root@desktop243 Desktop]# echo "Mayy Daly" >> names
    [root@desktop243 Desktop]# gawk '{print NF,$0}' names
    3 Tome Savage 100
    3 Molly Lee 200
    3 John Doe 300
    2 Mayy Daly
    变量 NR: 每条记录的行号,处理完一行将会加 1,所以全部处理完后可以理解成行数的总数
    [root@desktop243 Desktop]# gawk '{print NR,": ->",$0}' /etc/passwd
    1 : -> root:x:0:0:root:/root:/bin/bash
    2 : -> bin:x:1:1:bin:/bin:/sbin/nologin
    …… ……
    38 : -> student:x:500:500::/home/student:/bin/bash
    39 : -> visitor:x:501:501::/home/visitor:/bin/bash

    字段分隔符

    • FS 内部变量:
    – 保存着输入字段的分隔符的值 (OFS 则代表输出的分隔符)
    – 默认使用空格或制表符来分隔字段
    – 在 BEGIN 语句段中设置 FS 的值
    实例:
    [root@desktop243Desktop]# cat /etc/passwd | gawk 'BEGIN{FS=":";print"--count
    normal user now--"}$3 >= 500 { print $1;count++} END {printf("Total : %d
    Normal users
    ",count)}'
    --count normal user now--
    nfsnobody
    student
    visitor
    Total : 3 Normal users
    也可以在命令行中指定 -F 选项改变分隔符
    默认是以空格为分隔符
    [root@desktop243 Desktop]# gawk 'NR <= 4 {print NR,$1}' /etc/passwd
    1 root:x:0:0:root:/root:/bin/bash
    2 bin:x:1:1:bin:/bin:/sbin/nologin
    3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
    4 adm:x:3:4:adm:/var/adm:/sbin/nologin
    指定分隔符为“:”
    [root@desktop243 Desktop]# gawk -F : 'NR <= 4 {print NR,$1}' /etc/passwd
    1 root
    2 bin
    3 daemon
    4 adm
    • 使用多个字符分隔符,写在括号中,下面的例子使用空格,冒号和制表符
    – gawk -F'[ : ]' '{print $1, $5, $7 }' /etc/passwd

    模式

    awk模式用来控制输入的文本行执行什么样的操作
    • 模式为正则表达式
    • 模式具有着隐式 if 语句
    • 模式写在模式操作符两个 "//"中
    实例:
    [root@desktop2 Desktop]# gawk '/^root/' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    [root@desktop2 Desktop]# gawk '/^root/ || /^student/' /etc/passwd
    root:x:0:0:root:/root:/bin/bash
    student:x:500:500::/home/student:/bin/bash
    [root@desktop2 Desktop]# gawk -F: '/student/{print $1":"$3}' /etc/passwd
    student:500
    [root@desktop2 Desktop]# gawk '/^sshd/,/^stude*/' /etc/passwd
    sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
    nslcd:x:65:55:LDAP Client User:/:/sbin/nologin
    tcpdump:x:72:72::/:/sbin/nologin
    pulse:x:496:494:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
    gdm:x:42:42::/var/lib/gdm:/sbin/nologin
    student:x:500:500::/home/student:/bin/bash

    操作

    • 格式
    模式 { 操作语句 1; 操作语句 2; ...... ;}
    • 或者
    模式 { 操作语句 1 操作语句 2 ...... }

    正则表达式

    • 很多地方都是用到正则表达式来匹配特定的信息
    ^ 串首
    $ 串尾
    . 匹配单个任意字符
    * 匹配零个或多个前面的字
    + 匹配一个或多个前面的字符
    ? 匹配零个或一个前面的字符
    [ABC] 匹配括号中给出的任一个字符
    [A-Z] 匹配 A到 Z之间的任一个字符
    A|B 匹配二选一,或者的意思,等同于[AB]
    (AB)+ 匹配一个或多个括号中的组合
    * 星号本身,转义星号本身

    匹配操作符

    • 前面介绍了模式,也可以对特定的列使用模式匹配符"~",与条件做比较
    • 语法:
    • ~//
    或者
    !~ / /
    [root@desktop2 Desktop]# gawk -F: '$1 ~ /[sS]tud*/{print $1":"$3}' /etc/passwd
    student:500

    POSIX 字符类表达式

    [[:allnum:]] 字母和数字字符 [A-Za-z0-9]
    • [[:alpha:]] 字母字符等同于[A-Za-z]
    • [[:cntrl:]] 控制字符
    • [[:digit:]] 数字字符 [0-9]
    • [[:graph:]] 非空白字符(空格,控制字符等)
    • [[:lower:]] [[:upper:]] 小写/大写字母
    • [[:space:]] 所有的空白字符(换行符,空格,制表符)
    一般不会用这些,这些不好记。
    gawk 'BEGIN { FS=":"} $1 ~ /^[[:digit:]]+$/ {print $0 }' /etc/inittab
     

    awk 脚本

    • 如果有多条 awk的模式或指令要处理,将它们都写在脚本中
    • #为注释符
    • 一行多条命令要用分号隔开
    • 操作跟在模式之后的话,必须一行书写完(即左大括号在同一行)
    [root@desktop2 Desktop]#vim info
    #!/bin/gawk
    # The first awk script
    /student/ { print "Studentid is" , $2}
    /vistor/ {print "vistor id is", $2}
    运行:
    [root@desktop2 Desktop]#gawk -F: -f info /etc/passwd

    比较表达式

    用来对文本做比较,只有条件为真,才执行指定的动作
    • < gawk '$3 < 500' /etc/passwd #系统帐户
    • <= gawk '$3 <= 499' /etc/passwd #同上
    • == gawk '$3 == 0' /etc/passwd #id 为 0,root 帐户
    • != gawk '$3 != 500' /etc/passwd #非 id=500 的帐户
    • >= gawk '$3 >= 500' /etc/passwd #普通帐户
    • > gawk '$3 > 499' /etc/passwd #同上
    • ~ gawk '$1 ~ /^root/' /etc/passwd #root 帐户
    • !~ gawk '$1 !~ /^root/' /etc/passwd #非 root 帐户

    条件表达式

    • 格式:条件表达式 1?表达式 2:表达式 3
    • 与之等同的代码段如下
    {
    if (条件表达式 1 成立)
    表达式 2
    else
    表达式 3
    }
    实例:
    [root@desktop2Desktop]#echo "111 333"| gawk '{max=$1>$2?$1:$2;print max}'
    333
    [root@desktop Desktop]# cat /etc/passwd | gawk -F: '{printf("%s is %s
    user
    ",$1,$3 >= 500?"Normal":"System") }'
    rootis System user
    bin is System user
    …… ……
    student is Normal user
    visitor is Normal user

    算术运算

    可以在模式中执行计算操作
    awk '$3 / 1024 > 2000' filename
    + 加 10+2 =12
    - 减 10-2 =8
    * 乘 10*1024 =10240
    / 除 10240/1024 =10
    % 求模(求余数) 10%3=1
    ^ 次方 2^3=8

    逻辑操作符

    逻辑操作符用来测试模式的真假
    && 逻辑与 1&&0 FALSE
    || 逻辑或 1 || 0 TRUE
    ! 逻辑非 !0 TRUE
    awk -F: '$3 >500 && $3 <= 550' /etc/passwd
    awk -F: '$3 ==100 || $3 > 50'

    范围模式

    范围模式提供了选择一段数据操作的可能
    • 先匹配第一个模式,将作为开始部分
    • 接着匹配第二个模式,作为结束
    • 之间的这一段将选中做操作
    • 模式与模式之间使用","逗号间隔
    awk '/operator/,/nobody/' /etc/passwd

    验证数据的有效性

    验证数据的有效性可以综合我们之前所学的判断方式
    • 判断有效数据是否为七列,可以通过检测 NF 内部变量
    实例:找出 employees数据表中的缺空数据
    [root@shiyan ~]# cat employees
    Name Numbers Time Price
    Tome 24 2008/10/12 3000
    Marry 38 2008/11/8 5433
    Molly 70 2009/2/17 3421
    John 55 2009/4/9 5646
    Tome 65 2009/8/7
    Molly 45 2009/9/21
    John 77 2009/10/8 5687
    [root@shiyan ~]# gawk 'NF !=4 {print NR,": has only",NF,"fileds"}' employees
    6 : has only 3 fileds
    7 : has only 3 fileds
    • 判断是否为字母开头
    awk '$1 ~ /^[a-zA-z]+/ {.....}' filename
    • 判断数值是否大于某值
    awk '$4 > 200 {......}' filename

    数值变量和字符串变量

    字符串写下双引号中,比如"Hello world"
    • 默认将一个字符串转化成数字时,将变成 0
    –name = "Nancy" #name 此时为字符串
    –x++ #x 是数字,初始值为 1
    –number = 35 #number 是数字
    • 强行转化
    –name + 0 #name 此时变成数字 0
    –number " " #number 此时为字符

    用户自定义变量

    变量名可以是字母数字和下划线组成,但不能以数字开头。
    • awk将字符串变量初始化为空字符串 ""
    • 数值变量初始化为 0
    • 格式
    –变量 = 表达式
    [root@sya ~]#gawk'$1~/^T/{wage=$2*$4;print$1,$3,"wage:",wage}' ./employees
    Tome 2008/10/12 wage: 72000
    Tome 2009/8/7 wage: 0

    BEGIN 模式

    BEGIN 模式后面跟了一个程序段
    • 对输入文件进行任何处理之前,先执行 BEGIN 程序段
    • 用来修改内部变量(OFS,RS,FS)等的 值
    • 用来初始化用户变量和打印标题等
    [root@shiyan ~]# gawk 'BEGIN{FS=":";OFS="		";ORS="
    ****
    "} NR >=20 &&
    NR <= 23{print $1,$NF}' /etc/passwd
    smmsp /sbin/nologin
    ****
    nscd /sbin/nologin
    ****
    oprofile /sbin/nologin
    ****
    pcap /sbin/nologin
    ****
    [root@desktop1 Desktop]# echo "$(date +%F)" | gawk 'BEGIN{FS="-";} 
    > { print $1"/"$2"/"$3}'
    2011/10/18
    甚至无需文件名
    [root@shiyan ~]# gawk 'BEGIN{print "Hello World"}'
    Hello World

    END 模式

    不匹配任何输入行
    • 在 awk处理完输入行之后执行
    [root@shiyan ~]# gawk 'END{print "Total user:",NR}' /etc/passwd
    Total user: 36
    实例:查看虚拟主机有几台:
    [root@shiyan ~]#gawk '/^<Virt/ { total++ } END { print total, virtual hosts }'
    /etc/httpd/httpd.conf
    2 virtual hosts

    输出重定向

    可以将 awk 的输出重定向到 Linux 文件中
    • 目标文件必须用双引号括起来
    • "> " 清空文件,写入 awk信息,awk程序执行完毕后才关闭文件
    • ">>" 追加内容
    实例:将 employees 文件中的错误数据向屏幕输出,正确数据则将每个人每天的总金额输出到/root/cc 文件中:
    [root@shiyan ~]# vim rw.awk
    #!/bin/gawk
    { 
    if ( NF !=4 ) 
    { 
    print "Line",NR,":missing some info" 
    }else{ 
    print $1,"saled:",$2*$4 > "/root/cc"
    } 
    }
    测试:
    [root@shiyan ~]# gawk -f rw.awk employees
    Line 5 :missing some info
    Line 6 :missing some info
    [root@shiyan ~]# cat cc
    Tome saled: 72000
    Marry saled: 206454
    Molly saled: 239470
    John saled: 310530
    John saled: 437899

    输入重定向-读输入 getline

    从标准输入,管道或文件中读取输入
    • 读取每一行,重置 NF,NR 和 FNR 内部变量
    • 有内容读取到,返回 1 (为真值)
    • 读到 EOF(文件末尾) 返回 0 (为假值)
    • 发生错误,返回 -1
    [root@shiyan ~]# gawk 'BEGIN{"date"| getline DATE}{print DATE,$1,$7}'
    /etc/passwd
    20111015 日 星期六 09:41:49 CST root:x:0:0:root:/root:/bin/bash
    20111015 日 星期六 09:41:49 CST bin:x:1:1:bin:/bin:/sbin/nologin
    …… ……
    [root@shiyan ~]# gawk 'BEGIN{"date +%F"| getline DATE}{print DATE,$1,$7}'
    /etc/passwd
    2011-10-15 root:x:0:0:root:/root:/bin/bash
    2011-10-15 bin:x:1:1:bin:/bin:/sbin/nologin
    …… ……
    实例:提示用户输入一个用户名,判断该用户是在/etc/passwd 中的哪一行:
    [root@shiyan ~]# gawk 'BEGIN{print"What is your name?";
    >getline name < "/dev/tty"}
    >$1 ~ name{print "Found",name,"online",NR".";
    >print"NIce to meet you",name,"@_@"}' /etc/passwd
    Whatis your name?
    student #getline 是重定向到终端接受的
    Found student online 34.
    NIce to meet you student @_@

    Bash 向 awk 发送参数

    getline 函数也可以从 Bash 命令发送的管道中获取参数
    • 语法:
    –getline 变量 < "-" # "-" 如同 tar 一样代表着管道过来的信息
    [root@shiyan ~]# echo "$(date +%F)"|gawk 'BEGIN{ FS=":";
    >getline D < "-"}NR>=33{print D" "$1"/"$3":"$7}' /etc/passwd
    2011-10-15 avahi-autoipd/100:/sbin/nologin
    2011-10-15 student/500:/bin/bash
    2011-10-15 visitor/501:/bin/bash
    2011-10-15 oracle/502:/bin/bash

    管道

    打开管道的前提是其他管道必须关闭,每次只能打开一个管道,这和 Linux 中一条命令无
    限次的使用管道不同
    • 管道右边的命令必须写在双引号之间
    [root@shiyan ~]# gawk '/^[^#:]+/{print $1}' /etc/hosts
    127.0.0.1
    172.24.205.191
    172.24.200.254
    172.24.254.254
    [root@shiyan ~]# gawk '/^[^#:]+/{print $1 |"ping -c2 "$1}' /etc/hosts
    PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
    64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.028 ms
    connect: Network is unreachable
    connect: Network is unreachable
    connect: Network is unreachable
    64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.037 ms
    --- 127.0.0.1 ping statistics ---
    2 packets transmitted, 2 received, 0% packetloss, time 999ms
    rtt min/avg/max/mdev = 0.028/0.032/0.037/0.007 ms

    关闭文件和管道

    要对 awk 程序中的某个文件或管道多次读写,得先关闭程序
    • awk程序在处理文件时会保持打开状态直到脚本结束。
    • END 块中也受管道影响。
    • 关闭文件或管道时的引号中的内容与打开文件或管道时的名称
    一致,甚至包括参数,空格
    • 使用 close()函数实现
    gawk '/^[^#]+/ { print $1 | "ping -c3 " $1 } END {close("ping -c 3 ")}' /etc/hosts

    system 函数

    • system()函数以 Linux 命令作为参数
    • 执行 Linux 命令之后将 Linux 命令 $? 退出值返回给 awk
    • 注意:函数中 Linux 命令必须用双引号
    [root@desktop1 Desktop]# gawk '/^[^#:]/{ if(system("ping -c2 "
    $1" > /dev/null")==0 ){print $1" is on line"}else{ print $1" is down"}}' /etc/hosts
    127.0.0.1 is on line
    172.24.0.2 is down
    172.24.200.254 is on line
    172.24.254.254 is on line
    
    注意里面的空格“ ” !

    if 语句

    • awk就如 C 语言,有着变量,条件判断和循环
    • if 语句是条件判断的关键字,默认为隐藏,
    • 格式
    if (判断的表达式)
    {
    语句 1;语句 2;…… #判断表达式(为真)成立而执行的代码段
    }
    实例:
    1、gawk -F: '{if( $3 >= 500) print $1 "is a normal user "}'/etc/passwd
    2、 gawk -F: '{ if ($3 >=500) {count++;} } END { print "Total normal user: "count }' /etc/passwd
     

    if/else 语句

    • if/else 语句实现了真与假的两重处理
    • 判断表达式为 1(真),与前面 if 语句相同
    • 为 0 (假)则执行 else 后面的代码段
    • 格式:
    if (判断表达式) {
    语句 1;语句 2;…… #判断表达式成立
    } else {
    语句 10,语句 11;…… #判断表达式不成立
    }
    实例 1:
    gawk -F: '{ if($3 >=500) { print $1 "is a normal user " } else { print $1 "is
    a system user "}' /etc/passwd
    实例 2:
    gawk -F: '{ if($3 < 500) { print $1 "is a system user " } else { print $1 "is a
    normal user "}' /etc/passwd
     

    if/else 和 else if 语句

    • 如果在计算多重判断的时候,我们还需要对 if/else 语句做扩充,在其后再加上 if else,做
    下一个判断
    语法
    if (判断表达式 1) {
    语句 1; 语句 2;…… #表达式 1 成立
    }else if (判断表达式 2) {
    语法 10;语法 11;...... #表达式 2 成立
    }else if (判断表达式 N...) {
    语法 N0;语法 N1;…… #表达式 N 成立
    }else {
    语法 Y1;语法 Y2;.... #以上都不成立
    }

    while 循环

    首先给初始一个变量,接着在 while 判断表达式中测试该变量,为 0(假)退出 while 循环;
    • 注意:代码段中要在一些情况下修改初始的变量值,否则是一个消耗 CPU 的死循环
    • 语法
    while(条件判断式){
    语句 1;语句 2;…… # 语句成立一直执行部分
    }
    [root@desktop Desktop]# gawk -F: '{print NR,":User info:
    ======";i=1;
    while(i<=NF){print $i;i++};print "
    "}' /etc/passwd
    1 :User info:
    ======
    root
    x
    0
    0
    root
    /root
    /bin/bash
    …… ……
    39 :User info:
    ======
    visitor
    x
    501
    501
    /home/visitor
    /bin/bash

    for 循环

    有着三个表达式,第一个为初始化变量,第二个做测试,第三个用来改变初始变量(如果缺少
    此部分,就得到代码段修改,否则是死循环)
    • 语法
    for(初始表达式; 判读表达式; 更新表达式) {
    语法 1; 语法 2; .....
    }
    [root@desktop Desktop]# gawk -F: '{print NR,":User info:
    ======";
    i=1;for(;i<=NF;i++){print $i};print "
    "}' /etc/passwd
    1 :User info:
    ======
    root
    x
    0
    0
    root
    /root
    /bin/bash
    2 :User info:
    ======
    bin
    x
    1
    1
    bin
    /bin
    /sbin/nologin
    …… ……

    循环控制

    break 用来终止循环
    • continue 语句 用来不做后续操作,绕过此次循环,继续下一循环
    实例:
    为了方便实验,创建一个/tmp/passwd:
    [root@localhost ~]# cat /tmp/passwd
    avahi-autoipd:x:100:103:avahi-autoipd:/var/lib/avahi-autoipd:/sbin/nologin
    student:x:500:500::/home/student:/bin/bash
    visitor:x:501:501::/home/visitor:/bin/bash
    harry:x:502:502::/home/harry:/bin/bash
    [root@desktop Desktop]# gawk -F: '{i=1;
    while(i++ < NF ){
    if($i~/daemon/)
    {print NR,$1;break;}
    }
    }' /etc/passwd
    3 daemon
    28 haldaemon
    31 avahi
    continue 语句:会将匹配的这行其他段打印出来,继续往下查询
    [root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
    while(i++ < NF){if($i~/student/){ print "========";continue; }
    else { print $i ;}}}'
    avahi-autoipd
    x
    100
    103
    avahi-autoipd
    /var/lib/avahi-autoipd
    /sbin/nologin
    ========
    x
    500
    500
    ========
    /bin/bash
    visitor
    x
    501
    501
    /home/visitor
    /bin/bash
    harry
    x
    502
    502
    /home/harry
    /bin/bash
    break 语句:匹配的这行其他段都不会打印,继续往下查询
    [root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;
    while(i++ < NF){if($i~/student/){ print "========";break; }
    else { print $i ;}}}'
    avahi-autoipd
    x
    100
    103
    avahi-autoipd
    /var/lib/avahi-autoipd
    /sbin/nologin
    ========
    visitor
    x
    501
    501
    /home/visitor
    /bin/bash
    harry
    x
    502
    502
    /home/harry
    /bin/bash

    next 语句

    在循环处理时,使用 next 语句,将会使 awk 中跳过 next 段
    以后本次的处理,执行下一个循环
    • 下面的例子将打印出除系统帐户以外的所有用户
    [root@desktop18 Desktop]# gawk -F: '{if($3<500){next;}else{print $1}}'
    /etc/passwd
    nfsnobody
    student
    visitor

    exit 语句

    exit 用来终止 awk 对后续内容的处理
    • exit 也可以返回具体的值,提供 Bash 做状态判断
    • 要注意,exit 退出不会绕过 END 块,换句话说 END块
    总会执行,对于要向 BASH 返回值的处理,使用以下的方法
    • 语法:
    –{ exit(1) }
    实例:
    exit,找到匹配的就会退出,返回 1,不再往下查询:
    [root@localhost ~]# cat /tmp/passwd | gawk -F: '{ i=0;while(i++ <
    NF){if($i~/student/){ print "========";exit(1); } else { print $i ;}}}'
    avahi-autoipd
    x
    100
    103
    avahi-autoipd
    /var/lib/avahi-autoipd
    /sbin/nologin
    ========
    [root@localhost ~]# echo $?
    1

    关联数组的下标

    • awk中的数组下标可以是数字,也可以是字符串
    • 数组和变量一样,需要的时候直接创建
    • 数组的下标数值由 0 开始
    [root@desktop18 Desktop]# vim employess
    Tom 234 2008/03/05 685
    Mary 451 2008/04/06 932
    Bill 127 2009/10/09 3456
    Mary 341 2009/10/18 4532
    Tom 465 2009/11/10 3421
    [root@desktop18 Desktop]# gawk '{ name[k++]=$1} END{for(i=0;i<NR;i++){
    printi,name[i]}}' employess
    0 Tom
    1 Mary
    2 Bill
    3 Mary
    4 Tom

    用字符串作为数组的下标

    • 专门用于数组的 for 循环,遍历数组
    • for(索引 in 数组)
    {
    –语句
    }
    打印出用户名和总工资:数组下标:字符串
    将用户名($1)相同的行的工资($4)相加
    [root@desktop18 Desktop]# gawk '{ name[$1]+=$4} END{for(Name in name){
    print Name,":",name[Name]}}' employess
    Tom : 4106
    Mary : 5464
    Bill : 3456

    处理命令行参数

    从命令行获得参数,ARGC代表参数的总数,ARGV数组用来保存输入的参数
    [root@desktop18 Desktop]# vim argvs
    #!/bin/gawk
    BEGIN{
    for ( i=0;i < ARGC ; i++ )
    { 
    printf( "ARGV[%d] is --> %s
    ",i,ARGV[i])
    }
    printf( "Total : %d parameters
    ",ARGC);
    }
    [root@desktop18 Desktop]# gawk -f argvs /etc /root 1234 172.24.200.254
    ARGV[0] is --> gawk
    ARGV[1] is --> /etc
    ARGV[2] is --> /root
    ARGV[3] is --> 1234
    ARGV[4] is --> 172.24.200.254
    Total : 5 parameters
    awk不会把 -f 以及后面的脚本认定为参数
    [root@desktop18 Desktop]# gawk -f argvs /etc "ls /root"
    ARGV[0] is --> gawk
    ARGV[1] is --> /etc
    ARGV[2] is --> ls /root
    Total : 3 parameters
    用 xargs来接收保存命令传来的参数并传递:(以空隔来分别参数)
    [root@desktop18 Desktop]# echo "172.24.200.254" | xargs ping -c2
    PING 172.24.200.254 (172.24.200.254) 56(84) bytes of data.
    From 192.168.117.167 icmp_seq=1 Destination Host Unreachable
    From 192.168.117.167 icmp_seq=2 Destination Host Unreachable
    --- 172.24.200.254 ping statistics ---
    2 packets transmitted, 0 received, +2 errors, 100% packetloss, time 3000ms
    pipe 2
    [root@desktop18 Desktop]# echo "172.24.200.254 /etc/passwd /root" | xargs
    gawk -f argvs
    ARGV[0] is --> gawk
    ARGV[1] is --> 172.24.200.254
    ARGV[2] is --> /etc/passwd
    ARGV[3] is --> /root
    Total : 4 parameters

    字符串 sub 和 gsub 函数

    sub 和 gsub 函数,可以在条目中查找与给定的正则表达式匹配的字符串,并取代它
    • sub 和 gsub 的区别是,前者只对匹配部分一次替换,后者为全部替换
    • 语法:
    –sub( 正则表达式 , 替换字符串) #默认为$0,整条记录
    –sub( 正则表达式,替换字符串 , 目标字段); #指定的字段
    换名字:
    [root@desk18Desktop]# gawk '{sub(/[Tt]om/,"ttooomm",$1);print $0}' employess
    ttooomm 234 2008/03/05 685
    Mary 451 2008/04/06 932
    Bill 127 2009/10/09 3456
    Mary 341 2009/10/18 4532
    ttooomm 465 2009/11/10 3421
    sub:只对匹配部分一次替换
    [root@desktop18 Desktop]# gawk '{sub(/0/,"kkkkk");print $0}' employess
    Tom 234 2kkkkk08/03/05 685
    Mary 451 2kkkkk08/04/06 932
    Bill 127 2kkkkk09/10/09 3456
    Mary 341 2kkkkk09/10/18 4532
    Tom 465 2kkkkk09/11/10 3421
    gsub 全部替换
    [root@desktop18 Desktop]# gawk '{gsub(/0/,"kkkkk");print $0}' employess
    Tom 234 2kkkkkkkkkk8/kkkkk3/kkkkk5 685
    Mary 451 2kkkkkkkkkk8/kkkkk4/kkkkk6 932
    Bill 127 2kkkkkkkkkk9/1kkkkk/kkkkk9 3456
    Mary 341 2kkkkkkkkkk9/1kkkkk/18 4532
    Tom 465 2kkkkkkkkkk9/11/1kkkkk 3421

    sub 函数示例

    • 注意正则表达式的使用方法
    • gawk '{ sub(/172.168.0./, "192.168.0." ); print}'/etc/sysconfig/iptables
    • gawk '{ sub(/Mac/,"MacIntosh",$1) ; print }' filename
    • gawk '{ gsub(/[Tt]om/, "Thomas" , $1); print }' datafile

    字符串长度 length 函数

    • length 函数取回字符串的字符数量
    • 格式
    –length(字符串)
    –length #不带参数,返回记录中的字符个数
    带参数:
    [root@desktop18 Desktop]# echo "123qwe" | gawk 'BEGIN{getline RR <"-";print
    length(RR)}'
    6
    [root@desktop18 Desktop]# gawk '{print $1,length($1)}' employess
    Tom 3
    Mary 4
    Bill 4
    Mary 4
    Tom 3
    不带参数:
    [root@desktop18 Desktop]# gawk '{print $1,length}' employess
    Tom 22
    Mary 23
    Bill 24
    Mary 24
    Tom 24

    字符 substr 函数

    • substr函数返回从字符串指定位置开始的一个子字符串。
    • 如果指定了子字符串的长度,返回字符串的对应的部分
    • 语法:
    –substr(字符串,起始位置)
    –substr(字符串,起始位置,子字符串长度)
    [root@desktop18 Desktop]# gawk '{print substr($1,2,length)}' employess
    om
    ary
    ill
    
    
    ary
    
    
    om
    
    
    [root@desktop18 Desktop]# gawk '{print substr($3,1,4)}' employess
    
    
    2008
    
    
    2008
    
    
    2009
    
    
    2009
    
    
    2009
    
    
    将 employess 中的日期换成另一种格式
    
    
    [root@desktop18 Desktop]# gawk '{print $1,$2,
    
    
    substr($3,9,2)"/"substr($3,6,2)"/"substr($3,1,4),$4}' employess
    
    
    Tom 234 05/03/2008 685
    
    
    Mary 451 06/04/2008 932
    
    
    Bill 127 09/10/2009 3456
    
    
    Mary 341 18/10/2009 4532
    
    
    Tom 465 10/11/2009 3421
     

    字符 match 函数

    • match 函数根据正则表达式返回其在字符串中出现的位置,未出现,返回 0
    • match 函数中变量
    RSTART 子字符串出现的起始位置
    RLENGTH 子字符串的长度
    而这些变量之后可以提供给 substr 来提取子字符串
    实例:文件中的时间格式不同的情况下需要提取年份
    [root@desktop18 Desktop]# gawk '{print $3}' employess 2008-03-05
    2008-04-06
    09/11/2009
    2009-10-18
    2009-11-10
    [root@desktop18 Desktop]# gawk '{match($3,/[12][0-9][0-9][0-9]/);
    print $1,substr($3,RSTART,RLENGTH)}' employess
    Tom 2008
    Mary 2008
    Bill 2009
    Mary 2009
    Tom 2009

    字符 split 函数

    • split 函数用来将一个字符串拆分成一个数组
    • 语法:
    –split(字符串, 保存数据的数组,字段分隔符)
    #注意 Split 函数切割的数组下标从 1 开始,0 永远为空
    –split(字符串, 保存数据的数组 ) #使用 FS 默认值
    [root@desktop18 Desktop]# cat database
    2010-04-22 car 10 1000
    2010-05-10 car 7 700
    2010-05-13 dog 8 80
    2010-06-11 bike 1 100
    统计 5 月份的销售总额:
    [root@desktop18 Desktop]# gawk '{
    >split($1,DATE,"-");
    > if(DATE[2] == 5){
    > count+=$4
    > }
    >}
    >END{
    > print "May : "count
    >}' database
    May : 780

    整数 int 函数

    • int 函数去掉小数点后面的数字,仅仅留下整数部分
    • 它不会做四舍五入操作
    [root@desktop18 Desktop]# gawk 'END {print 31/3}' database
    10.3333
    [root@desktop18 Desktop]# gawk 'END {printint(31/3)}' database
    10

    生成随机数

    • rand 函数生成一个大于或等于 0,小于 1 的浮点数
    • 当多次执行上面的脚本,每次都生成相同的数字
    • srand 函数,以当前时刻为 rand()生成一个种子
    • srand(x)把 x 设置为种子,通常,程序应该在运行过程中不断的改变 x 的值
    当没有种子时,生成的随机数不同文件相同行的随机数是一样的,文件有多少行就生成多少个随机数
    [root@desktop18 Desktop]# gawk '{print NR,rand()}' database
    1 0.237788
    2 0.291066
    3 0.845814
    4 0.152208
    [root@desktop18 Desktop]# gawk '{print NR,rand()}' /etc/passwd
    1 0.237788
    2 0.291066
    3 0.845814
    4 0.152208
    …… ……
    38 0.377663
    39 0.899756
    当有种子时,生成的随机数不同文件或同一文件相同行的随机数是不一样的,文件有多少行
    就生成多少个随机数
    [root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
    1 0.78965
    2 0.970641
    3 0.284081
    4 0.819256
    [root@desktop18 Desktop]# gawk 'BEGIN{srand()}{print NR,rand()}' database
    1 0.532605
    2 0.737259
    3 0.105589
    4 0.0879184

    技能掌握测试题:

    •1  分析下面数据中,打印出每个销售员 5 月销售的总额
    vi sales
    Tom 2010-04-09 car 6 6000
    Mary 2010-05-07 car 1 1000
    Tom 2010-05-20 bike 15 1500
    Mary 2010-05-22 car 2 2000
    Tom 2010-06-17 car 1 1000
     
    •2  以下的数据需要转成 SQL 语句,方便插入到数据库中,注意年月日的格式
    vi sales
    Tom 04/09/2010 car 6 6000
    Mary 05/07/2010 car 1 1000
    Tom 05/20/2010 bike 15 1500
    Mary 05/22/2010 car 2 2000
    SQL 格式
    insert into sales value('Tom',2010-04-09,'car',6,6000)
     
    题1:
    [root@desktop215 Desktop]# gawk '{
    > split($2,DATE,"-"); 先将日期的月份拆分成一个数组
    > if(DATE[2] == 5){
    > name[$1]+=$5}
    > }
    # 如果月份是 5 月,就将以姓名(字符串)为数组下标,将相同名字的销售额相
    > END{
    > for(Name in name){
    > print Name,": 05",name[Name]}
    > }' sales
    Tom : 05 1500
    Mary : 05 3000
    方法 2:
    [root@desktop215 Desktop]# gawk '
    $2 ~ /05/{name[$1]+=$5}
    END{
    for(Name in name){
    print Name,": 05",name[Name]}
    }' sales
    Tom : 05 1500
    Mary : 05 3000

    题二:

    [root@desktop215 Desktop]# gawk '{OFS="	"; print $1,
    substr($2,7,4)"-"substr($2,4,2)"-"substr($2,1,2),
    $3,$4,$5}' sales2 > /root/Desktop/sales3
    [root@desktop215 Desktop]# cat /root/Desktop/sales3
    Tom 2010-09-04 car 6 6000
    Mary 2010-07-05 car 1 1000
    Tom 2010-20-05 bike 15 1500
    Mary 2010-22-05 car 2 2000
    
    导入数据库:
    
    mysql> use bluefox;
    Database changed
    
    mysql> create table sale( name varchar(10), time date, spes varchar(10), num
    int(11), money int(11) );
    Query OK, 0 rows affected (0.11 sec)
    mysql> select * from sale;
    +------+------------+------+------+-------+
    | name | time | spes | num | money |
    +------+------------+------+------+-------+
    | Tom | 2010-04-09 | car | 6 | 6000 |
    | Mary | 2010-05-07 | car | 1 | 1000 |
    | Tom | 2010-05-20 | bike | 15 | 1500 |
    | Mary | 2010-05-22 | car | 2 | 2000 |
    +------+------------+------+------+-------+
    4 rows in set (0.00 sec)
  • 相关阅读:
    placeholder在ie浏览器里不显示的问题解决
    条件注释判断浏览器版本<!--[if lt IE 9]>
    在CSS中,BOX的Padding属性的数值赋予顺序为
    PhpStorm的注册码、Key
    关于【bootstrap modal 模态框弹出瞬间消失的问题】
    python 常见算法
    scrapy 爬虫基础
    python中的小知识点
    python 数据结构简介
    前端插件定制--表头和表内容
  • 原文地址:https://www.cnblogs.com/zoujiaojiao/p/10938735.html
Copyright © 2011-2022 走看看