Ubuntu小技巧15--awk命令详解

Ubuntu小技巧15–awk命令详解

1 基本介绍

Awk是一种用于处理数据和生成报告的UNIX编程语言。 Nawk是awk的较新版本,而gawk是Linux上使用的GNU版本。awk 的数据可以来自标准输入、一个或多个文件,也可以来自一个程序的输出。 其既可以在命令行上进行一些简单的操作,也可以将Awk写入到大型应用程序中。 由于awk可以处理数据,所以它是在shell脚本和管理小型数据库中必不可少的工具。 Awk从第一行到最后一行逐行扫描文件(或输入),搜索与指定模式匹配的行,并在这些行上执行选定的操作(用大括号括起来)。 如果存在没有特定操作的模式,则显示所有与该模式匹配的行;否则,将显示所有行。 如果存在没有特定模式的动作,则所有输入行多会被执行。

1.1 工作原理

测试文件:names

Tom Savage 100
Molly Lee 200
John Doe 300

案例: awk ‘{print $1,$3}’ names
结果:

Tom 100
Molly 200
John 300
  1. awk 从文件或者管道获取第一行作为输入信息,将其保存到内部变量$1中;默认,每一行都会保存为一个临时记录;如下图所示:
    变量$0
  2. awk 通过空格或者tab键将该行($0)拆分为多个区域(单词),每个区域都会存放到一个单独的内部变量中,依次从$1, $2, $3 … $n存储,最多可以存储100个变量。第一行存储如下:
    $0的存储内容
  3. awk内部有一个变量FS(field separator),它用于区分不同区域,FS默认为空格-tab键,即:默认通过空格和tab键隔离不同的区域;如果需要通过其它字符来隔离不同区域|单词,也可以修改FS的值。
  4. 将$0拆分后,通过print函数输出对应的值(实际中可以根据需要对数据进行处理输出),此处直接输出第1,3两个变量。
    {print $1,$3}
    如果两个变量之间使用’,’ 则输出之间会自动产生一个空格,如果没有’,‘则输出直接相连;
    此处$1和$3之间的’,‘映射到一个特殊的内部变量OFS(output field separator ), 其默认赋值为一个空格,因此添加’,'后输出自带空格。
  5. 当awk完成改行的输出后,其将再次获取下一行,并使用上述1-4的步骤进行处理;如此循环,直到最后一行被处理完。

1.2 使用格式

awk的使用格式如下:
awk ‘pattern’ filename
awk ‘{action}’ filename
awk ‘pattern {action}’ filename

案例1.2.1:
$date>date.txt
$cat date.txt
2020年 02月 16日 星期日 22:46:25 CST
$ cat date.txt|nawk ‘{ print "Month: " $2 "\nYear: " , $1 }’
结果:

Month: 02月
Year:  2020年

案例1.2.2:
数据employees

Tom Jones       4424      5/12/66     543354
Mary Adams      5346      11/4/63     28765
Sally Chang     1654      7/22/54     650000
Billy Black     1683      9/23/44     336500

结果:

$ nawk '/Sally/{print "\t\tHave a nice day, " $1, $2 "\!"}' employees
		Have a nice day, Sally Chang!

2 常用功能介绍

2.1 格式化输出

  1. print 函数
    案例2.1.1:date| awk ‘{ print "Month: " $2 "\nYear: " , $1 }’
    说明:输出月份和年

    案例2.1.2:awk ‘/Sally/{print "\t\tHave a nice day, " $1, $2 “!”}’ employees
    说明:匹配Sally开始的行,输出: Have nice day,Sally Chang

  2. OFMT变量
    OFMT变量用于控制输出的数字格式, 该功能也可以通过printf来实现.
    案例2.1.3:awk ‘BEGIN{OFMT="%.2f"; print 1.2456789, 12E-2}’
    说明:用于控制数字输出格式,小数点后2位
    结果: 1.25 0.12

  3. printf 函数
    该函数让用户可以按照指定格式对内容进行输出,类似于c语言中的printf 函数;
    其可用转化字符包括:
    |转换字符 |定义 |
    |–|--|
    | c | 字符 |
    | s | 字符串 |
    | d | 十进制 |
    | ld | 长整形十进制 |
    | u | 无符号十进制|
    | lu | 长整形无符号十进制 |
    | x | 十六进制 |
    | lx | 长十六进制 |
    | o | 八进制 |
    | lo | 长八进制 |
    | e | 使用科学计数法的浮点数 |
    | f | 浮点数 |
    | g | 浮点数,使用e后者f类型(自动占用最少空间) |
    其可用修饰器包括:
    | 字符 | 定义 |
    |–|--|
    | - | 左对齐 |
    | # | 八进制整数起始为一个0,十六进制整数起始为0x |
    | + | 对于转移字符为d,e,f,g的整数, 会显示其+或者- 符号 |
    | 0 | 显示的值填充为0,而非空格 |

    案例2.1.4 : echo “UNIX” | awk ’ {printf “|%-15s|\n”, $1}’
    说明: 输出UNIX,且左对齐占用15个字符,默认补充为空格,若无-则为右对齐;
    结果: |UNIX |

    案例2.1.5: awk ‘{printf “The name is: %-15s ID is %8d\n”, $1, $3}’ employees
    说明: 输出The name is: xx(占用15个字符,左对齐) ID is yy(占用8位切右对齐)
    结果:

    The name is: Tom             ID is     4424
    The name is: Mary            ID is     5346
    The name is: Sally           ID is     1654
    The name is: Billy           ID is     1683
    

2.2 从文件获取awk命令

将awk命令写入文件中,通过-f导入命令,然后执行;若文件中由多个处理规则|方法,则每个行数据都会被这些规则处理,然后输出.

假设存在 awkfile 文件,包含2行内容,

/^Mary/{print "Hello Mary"}
{print $1,$2,$3}

案例2.2.1 : awk -f awkfile employees
说明: 对每一行数据,先匹配是否一Mary开头,是则输出Hello Mary; 并输出第1-3个单词;
结果:

Tom Jones 4424
Hello Mary
Mary Adams 5346
Sally Chang 1654
Billy Black 1683

除此之外,若有多个 匹配模式和行为,则可以将这些内容逐行写到脚本文件中,然后通过-f导入. 脚本中可以使用#来注释不需要的内容.
假如由info脚本文件,内容如下:

# My first awk script by Jack Sprat
# Script name: info; Date: February 28, 2004
/Tom/{print  "Tom's birthday is "$3}
/Mary/{print NR, $0}
/^Sally/{print "Hi Sally. "  $1 " has a salary of  $" $4 "."}
# End of info script

第1,2,6为注释内容,3,4,5为对的awk模式和行为, NR标志当前为第几行.
案例2.2.2: awk -f info employees
说明: 对每一行,分别用3,4,5对应的规则进行匹配,匹配到则执行对应的行为.
结果:

Tom's birthday is 4424
2 Mary Adams      5346      11/4/63     28765
Hi Sally. Sally has a salary of  $7/22/54.

2.3 模式和动作

  • 模式
    awk中的模式可以为正则表达式,或者一个条件表达式, awk的每行会对使用模式进行判断,符合要求则输出.

    案例 2.3.1: awk ‘/Tom/’ employees
    说明: 匹配到Tom则输出改行,等价于 awk ‘$0 ~ /Tom/{print $0}’ employees
    结果: Tom Jones 4424 5/12/66 543354
    注意: 等价表达中~ 为匹配符, 即从$0中匹配正则表达/Tom/

    案例2.3.2: awk ‘$3 < 4 000’ employees
    说明: 匹配到$3小鱼4000的行,并输出
    结果:

    Sally Chang     1654      7/22/54     650000
    Billy Black     1683      9/23/44     336500
    
  • 动作
    awk中动作为{}包围的语句, 动作既可以由模式触发,又可以单独使用, 还可以多个动作同时使用(多个动作之间使用;隔开). 其格式为 {action}

    案例2.3.3: date | awk ‘{print $1, $2, $3}’
    说明: 输出 年 月 日

    案例2.3.4: date | awk ‘{print $1; print $2}’
    说明: 2个动作,分行输出 年 月; 等价于 date | awk ‘{print $1};{print $2}’

    案例2.3.5: awk ‘/Tom/ {print “hi tom!”}’ employees
    说明: 匹配到Tom后才执行动作,输出hi tom!

2.4 正则表达

awk的模式中支持正则表达式, 基本用法大致同grep的正则表达类似; 若某一行输入被正则匹配到,则会执行正则对应的行为; 若正则后没有对应的行为,则直接输出匹配的行.
以下为awk支持的正则标志和作用:

MetacharacterWhat it does
^从字符串起始开始匹配
$从字符串结尾开始匹配
.匹配一个字符
*匹配0或者多个之前的字符
+匹配至少1个之前的字符
?匹配0这这1个之前的字符
[ABC]匹配任何一个在集合中的字符
[ABC]匹配任何一个不在集合中的字符
[A-Z]匹配任何一个在A-Z 范围的字符
A|B匹配A或者B
(AB)+匹配至少1个集合AB例如AB,ABAB,ABABAB等
\*匹配字符 * 符号
&用于保存搜索的字符串, 多配合替换功能

注: awk 不支持: \< >/ , \( \) , \{ \} 等3种正则用法;

案例2.4.1: awk ‘/Mary/’ employees
说明: 输出包含Mary的行

案例2.4.2: awk ‘/^[A-M][a-z]+ /’ employees
说明: 匹配 以大写A-M之间字符开头,紧接着至少1个小写字母,随后一个空格 的行
结果:

Mary Adams      5346      11/4/63     28765
Billy Black     1683      9/23/44     336500

3 经典案例

  1. 文本信息打印
    打印文件的第一列(域) : awk ‘{print $1}’ filename
    打印文件的前两列(域) : awk ‘{print $1,$2}’ filename
    打印完第一列,然后打印第二列 : awk ‘{print $1 $2}’ filename
    打印文本文件的总行数 : awk ‘END{print NR}’ filename
    打印文本第一行 :awk ‘NR==1{print}’ filename
    打印文本第二行第一列 :sed -n “2, 1p” filename | awk ‘print $1’
  2. 进程信息处理
    关闭wps相关所有进程:ps -ef|grep wps|awk ‘{print $2}’|xargs kill
  3. awk练习题
    数据源 data.txt 内容如下:
     wang     4
     cui      3
     zhao     4
     liu      3
     liu      3
     chang    5
     li       2
    
    1 通过第一个域找出字符长度为4的
    2 当第二列值大于3时,创建空白文件,文件名为当前行第一个域$1 (touch $1)
    3 将文档中 liu 字符串替换为 hong
    4 求第二列的和
    5 求第二列的平均值
    6 求第二列中的最大值
    7 将第一列过滤重复后,列出每一项,每一项的出现次数,每一项的大小总和
    1、字符串长度
    awk ‘length($1)==“4”{print $1}’
    2、执行系统命令
    awk ‘{if($2>3){system ("touch "$1)}}’
    3、gsub(/r/,“s”,域) 在指定域(默认$0)中用s替代r (sed ‘s///g’)
    awk ‘{gsub(/liu/,“hong”,$1);print $0}’ a.txt
    4、列求和
    df -h | awk ‘{a+=$2}END{print a}’
    5、列求平均值
    df -h | awk ‘{a+=$2}END{print a/NR}’
    df -h | awk ‘{a+=$2;b++}END{print a,a/b}’
    6、列求最大值
    df -h | awk ‘BEGIN{a=0}{if($2>a) a=$2 }END{print a}’
    7、将第一列过滤重复列出每一项,每一项的出现次数,每一项的大小总和
    awk ‘{a[$1]++;b[$1]+=$2}END{for(i in a){print i,a[i],b[i]}}’
  4. 使用特定区域分隔符
    案例: cho ‘Tom Jones:4424:5/12/66:543354’|awk -F: ‘/Tom Jones/{print $1,$2}’
    结果: Tom Jones 4424
    说明: -F: 制定分隔符为:, 默认为空格或者tab符.
  5. 匹配操作符(~)
    匹配操作符号~, 其作用为: 让一个正则从一条记录或者一个区域中进行匹配.
    案例: awk ‘$1 ~ /[Bb]ill/’ employees
    说明: 说明, 匹配第一个区域, 包括Bill或者bill , 注意$1 表示只用$1 进行匹配,若该为$0 这用一条记录进行匹配.
    结果: Billy Black 1683 9/23/44 336500

4 注意事项

  1. 后续将在此处增加awk使用中常见的注意事项

5 说明

测试系统版本:Ubuntu 1910 SERVER (64-bit)
参考文献: UNIX® Shells by Example Fourth Edition By Ellie Quigley

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昕光xg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值