Linux三大剑客之awk

版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢

一、概述

awk的名称来源于其最初设计者Alfred V. Aho, Peter J. Weinberger, and Brian W. Kernighan的姓氏。awk最原始的版本是1977年在AT&T贝尔实验室诞生的,awk经过改进生成的新的版本nawk,gawk,现在默认linux系统下日常使用的是gawk。我目前使用的操作系统为CentOS Linux release 7.2.1511,系统自带的awk版本为:GNU awk 4.0.2。

二、awk的用途

  • 文本处理。
  • 格式化输出文本、报告。
  • 数字运算(在我之前的文章中,探讨过整数的算术运算,浮点运算可以使用awk)。
  • 执行字符串操作。

三、系统内几个有关awk命令的区别与联系

通过命令,我们可以看到:

[awk@GeekDevOps ~]$ ls -l /bin/*awk
lrwxrwxrwx. 1 root root      4 11月 20 10:41 /bin/awk -> gawk
-rwxr-xr-x. 1 root root 514136 6月  10 2014 /bin/dgawk
-rwxr-xr-x. 1 root root 428576 6月  10 2014 /bin/gawk
-rwxr-xr-x. 1 root root   3188 6月  10 2014 /bin/igawk
-rwxr-xr-x. 1 root root 428600 6月  10 2014 /bin/pgawk

与awk有关的命令竟然有这么多!在用whatis命令看一下这些都是些什么鬼:

[awk@GeekDevOps ~]$ whatis awk gawk dgawk pgawk igawk
awk (1)              - pattern scanning and processing language
gawk (1)             - pattern scanning and processing language
dgawk (1)            - pattern scanning and processing language
pgawk (1)            - pattern scanning and processing language
igawk (1)            - gawk with include files

不太确信以上结果,我又使用man、info挨个看了一下,结果awk、gawk、dgawk、pgawk都是gawk,在线手册一模一样。唯独igawk与前面四个不太一样,是包含文件的gawk,其实也是gawk。awk是gawk的一个软连接,大家都是gawk!

四、awk的使用

4.1 理解awk的工作原理

Read

awk从输入流(文件,管道或者标准输入)中读取一行,然后存储到内存中。

Execute

所有的AWK命令都依次在输入文本上执行。默认情况下,awk会对每一行执行命令,可以通过提供模式限制这种行为。

Repeat

处理过程不断重复,从首行开始直到到达文件结尾。

创建marks.txt文件备用:

[awk@GeekDevOps ~]$ echo "1)  Amit    Physics  80
> 2)  Rahul   Maths    90
> 3)  Shyam   Biology  87
> 4)  Kedar   English  85
> 5)  Hari    History  89">marks.txt
4.2 awk的结构

BEGIN 语句块

BEGIN语句块的语法:

BEGIN {awk-commands}

BEGIN语句块在程序开始的使用执行,只执行一次,在这里可以初始化变量。BEGIN是AWK的关键字,因此它必须为大写。注意,这个语句块是可选的。

BODY 语句块

BODY语句块的语法:

/pattern/ {awk-commands}

BODY语句块中的命令会对输入的每一行执行,也可以通过提供模式来控制这种行为。注意,BODY语句块没有关键字。

END 语句块

END语句块的语法:

END {awk-commands}

END语句块在程序的最后执行,END是AWK的关键字,因此必须为大写,它也是可选的。

结合以上2点,举个例子来理解一下:

[awk@GeekDevOps ~]$ awk BEGIN'{printf "Sr NO\tName\tSub\tMarks\n"} {print} END{print "Done!"}' marks.txt
Sr NO   Name    Sub     Marks
1)  Amit    Physics  80
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89
Done!
[awk@GeekDevOps ~]$ awk BEGIN'{printf "Sr NO\tName\tSub\tMarks\n"} END{print "Done!"}' marks.txt
Sr NO   Name    Sub     Marks
Done!

在本例中,BEGIN块被执行一次,给文本内容增加了一行标题。body块从文本第一行扫描直至文件末尾。END块也仅仅执行了一次。

4.3 使用awk

通常情况下,awk命令较简短时我们直接按照以下方式执行awk命令:

awk 'program' input-file1 input-file2 …

如果awk内容较多的话,我们以以下格式来执行awk命令(此处program-file为awk脚本内容):

awk -f program-file input-file1 input-file2 …

awk是一门解释型的语言,所以也可以像执行bash shell一样执行awk脚本:

#!/bin/awk -f
BEGIN{print "My name is Ivan Du!"}
[awk@GeekDevOps ~]$ chmod u+x GeekDevOps.awk
[awk@GeekDevOps ~]$ ./GeekDevOps.awk
My name is Ivan Du!
4.4 打印某列或某字段
[awk@GeekDevOps ~]$ cat best.txt
www     CC      ICBC
[awk@GeekDevOps ~]$ awk '{print $1}' best.txt
www
[awk@GeekDevOps ~]$ awk '{print $3}' best.txt
ICBC
[awk@GeekDevOps ~]$ awk -F "\t" '{print $3}' best.txt
ICBC

默认情况下,awk以空格、制表符等符号为分隔符。从每一行的第一个字符串开始扫描,第一个字符串为1,第N个字符串为1,第N个字符串为1,第N个字符串为n,如果首行是空格之类的字符那也算。

4.5 打印匹配模式的列

当模式匹配成功时,默认情况下awk会打印该行,但是也可以让它只打印指定的字段。例如,下面的例子中,只会打印出匹配模式的第三和第四个字段。

[awk@GeekDevOps ~]$ awk '/a/ {print $3 " " $4}' marks.txt
Maths 90
Biology 87
English 85
History 89

匹配指定文件中带u的行,并打印第四列与第三列,中间以一个横向制表符隔开。

[awk@GeekDevOps ~]$ awk '/u/ {print $4"\t"$3}' marks.txt
90      Maths
4.6 统计文本总行数
[awk@GeekDevOps ~]$ awk 'BEGIN{ct=0} {++ct} END{print "Count:",ct}' marks.txt
Count: 5

此行命令中,BEGIN部分其实是可以省略的。

4.7 打印匹配模式的总行数
[awk@GeekDevOps ~]$ awk '/a/ {++ct} END{print "Count:",ct}' marks.txt
Count: 4

此处的BEGIN部分不能出现,否则报错。

4.8 打印超过指定长度的行
[awk@GeekDevOps ~]$ awk 'length($0) > 22' marks.txt
1)  Amit    Physics  80
2)  Rahul   Maths    90
3)  Shyam   Biology  87
4)  Kedar   English  85
5)  Hari    History  89

mark.txt文件是通过空格来控制对齐的,每一行加上空格一共是22个字符。

4.9 ARGC命令行参数个数
[awk@GeekDevOps ~]$ awk 'BEGIN{print "Arguments=" ARGC}' One Two Three Four
Arguments=5
4.10 ARGV命令行参数数组
[awk@GeekDevOps ~]$ awk 'BEGIN{for (i=0 ;i<ARGC-1;++i ){printf "ARGC[%d]=%s\n",i,ARGV[i]}}' One Two Three Four
ARGC[0]=awk
ARGC[1]=One
ARGC[2]=Two
ARGC[3]=Three
4.11 ENVIRON环境变量
[awk@GeekDevOps ~]$ awk 'BEGIN{print ENVIRON["PATH"]}'
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/awk/.local/bin:/home/awk/bin
4.12 FILENAME当前文件名
[awk@GeekDevOps ~]$ awk 'END{print FILENAME}' marks.txt 
marks.txt

注意:此处使用的是END,如果省略则会打印出5个文件名称,这个文件一5行。

4.13 常用的awk内置变量

变量名

属性

$0

当前记录

1−1−1-n

当前记录的第N个字段

FS

读入字段的分隔符,默认为空格

RS

读入记录分隔符,默认为换行符

NF

列,当前记录中的字段个数

NR

行,已经读出的行数,也就是行号

OFS

输出字段分隔符,默认为空格

ORS

输出记录分隔符,默认为换行符

[awk@GeekDevOps ~]$ awk -F " " '{print $4}' marks.txt 
80
90
87
85
89
[awk@GeekDevOps ~]$ awk '{print $3}' marks.txt 
Physics
Maths
Biology
English
History
[awk@GeekDevOps ~]$ awk 'BEGIN{FS=" "}{print $3}' marks.txt 
Physics
Maths
Biology
English
History

以上三种写法都是一样的效果。

[awk@GeekDevOps ~]$ ls -al | awk 'BEGIN{size=0}{size+=$5}END{print size/1024/1024 "MB"}'
128.017MB
[awk@GeekDevOps ~]$ ls -al|awk 'NR>1{size+=$5} END{print size/1024/1024 "MB"}'
128.017MB
[awk@GeekDevOps ~]$ ls -al|awk 'NR==1{print $2/1024 "MB"}'
128.035MB

以上两个代码片中,都是统计当前目录下所有的文件(包括隐藏文件)所占磁盘空间的大小,非常有用。

[awk@GeekDevOps ~]$ awk 'BEGIN{print "OFS=" OFS}' marks.txt
OFS=
4.14 awk中的算术运算

在awk中,支持像C语言中一样的算术运算。在前面的文章中介绍过,Linux系统中无法对非整型数字直接进行算术运算,要对浮点型的数据就行算术运算我们可以使用awk来实现。

[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;B=7;print A/B}'
0.4

在这一部分中,awk中的增减运算符、赋值运算符、关系操作符、逻辑运算符、三元操作符等均与C语言类似,不赘述。

4.15 awk中的一元操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=+A;print A}'
2.8
4.16 awk中的指数操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=A^3;print A}'
21.952
[awk@GeekDevOps ~]$ awk 'BEGIN{A=2.8;A=A**3;print A}'
21.952
4.17 awk中的字符串连接操作符
[awk@GeekDevOps ~]$ awk 'BEGIN{str1="Hello";str2=",GeekDevOps";str3=str1 str2;print str3}'
Hello,GeekDevOps
4.18 awk中的数组

数组的定义与C语言有类似的地方,也有差别,使用的时候需要注意一下,有的资料上说awk中不支持多维数组,通过awk的GUN的文档,我们可以看到,awk也是支持多维数组的。删除数组元素使用delete语句:

[awk@GeekDevOps ~]$ awk 'BEGIN{array[0][0]=2;array[0][1]=3;array[1][0]=4;array[1][1]=8;for(i=0;i<2;i++){for(j=0;j<2;j++){printf "array[%d][%d]=%d\n",i,j, array[i][j]}}delete array[0][0];print array[0][0] "\t" array[0][0]}'
array[0][0]=2
array[0][1]=3
array[1][0]=4
array[1][1]=8
4.19 awk中的控制结构

在awk中,也支持类似C语言一样的程序结构,支持if-else、while、do-while、for、switch、break、continue、nex、nextfile、exit。相信很多小伙伴都学习过C语言,与C语言一样的就不在赘述。

[awk@GeekDevOps ~]$ awk 'NF != 4 {
    printf("%s:%d: skipped: NF != 4\n", FILENAME, FNR) > "/dev/stderr"
    next
}'

-:1: skipped: NF != 4

-:2: skipped: NF != 4
...
[awk@GeekDevOps ~]$ awk 'BEGIN {
    if (("date" | getline date_now) <= 0) {
        print "Can not get system date" > "/dev/stderr"
        exit 1
    }
    print "Current date is", date_now
    close("date")
}'
Current date is 2018年 02月 28日 星期三 23:05:16 CST
4.20 awk中的函数

在awk中,支持内建函数与用户自定义函数。

常用数学计算函数

atan2(y, x)

Return the arctangent of y / x in radians. You can use ‘pi = atan2(0, -1)’ to retrieve the value of pi.

cos(x)

Return the cosine of x, with x in radians.

exp(x)

Return the exponential of x (e ^ x) or report an error if x is out of range. The range of values x can have depends on your machine’s floating-point representation.

int(x)

Return the nearest integer to x, located between x and zero and truncated toward zero. For example, int(3) is 3, int(3.9) is 3, int(-3.9) is -3, and int(-3) is -3 as well.

log(x)

Return the natural logarithm of x, if x is positive; otherwise, return NaN (“not a number”) on IEEE 754 systems. Additionally, gawk prints a warning message when x is negative.

rand()

Return a random number. The values of rand() are uniformly distributed between zero and one. The value could be zero but is never one.

sin(x)

Return the sine of x, with x in radians.

sqrt(x)

Return the positive square root of x. gawk prints a warning message if x is negative. Thus, sqrt(4) is 2.

srand([x])

Set the starting point, or seed, for generating random numbers to the value x. 

字符串函数

asort(arr [, d [, how] ])
asorti(arr [, d [, how] ])
gsub(regex, sub, string)
index(str, sub)
length(str)
match(str, regex)
split(str, arr, regex)
sprintf(format, expr-list)
strtonum(str)
sub(regex, sub, string)
substr(str, start, l)
tolower(str)
toupper(str)

时间函数

systime
mktime(datespec)
strftime([format [, timestamp[, utc-flag]]])

字节操作函数

and
compl
lshift
rshift
or
xor

自定义函数类似于C语言,参阅GUN网站function部分。

4.21 awk中的正则表达式
[awk@GeekDevOps ~]$ echo -e "My name is IVAN DU.\nMy blog is GeekDevOps.\nWelcome to my blog."|awk '/My+/'
My name is IVAN DU.
My blog is GeekDevOps.
[awk@GeekDevOps ~]$ echo -e "My name is IVAN DU.\nMy blog is GeekDevOps.\nWelcome to my blog."|awk '/^W/'
Welcome to my blog.

五、参考资料

https://www.tutorialspoint.com/awk/index.htm https://www.gnu.org/software/gawk/manual/gawk.html https://en.wikipedia.org/wiki/AWK#Sum_last_word

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java思维导图

Java 单例以及单例所引发的思考

1 前言 前几天无意中看到一篇文章,讲到了老生常谈的单例,抱着复习一下的心态点了进去,还是那些熟悉的内容,可是却发现自己思考的角度变了,以前更多的是去记忆,只停...

2877
来自专栏用户2442861的专栏

初学Redis(2)——用Redis作为Mysql数据库的缓存

http://blog.csdn.net/qtyl1988/article/details/39519951

1632
来自专栏Golang语言社区

go语言的sql包原理与用法分析

本文实例讲述了go语言的sql包原理与用法。分享给大家供大家参考,具体如下: go的sql包是在pkg/database中,里面的两个包sql和sql/driv...

4446
来自专栏coolblog.xyz技术专栏

自己动手实现一个简单的JSON解析器

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。相对于另一种数据交换格式 XML,JSON 有着诸多优点。比如易读...

66419
来自专栏恰同学骚年

Hadoop学习笔记—7.计数器与自定义计数器

  在上图所示中,计数器有19个,分为四个组:File Output Format Counters、FileSystemCounters、File Input...

1072
来自专栏程序员叨叨叨

【PHP】Propel的使用,看这一篇就够了

本文为学习Propel框架使用的笔记,默认已经安装好Propel环境,若有读者不知如何安装Propel,可参考《听说你PHP配置Composer遇到了一些困境》...

3455
来自专栏Android知识点总结

自己写一个svg转化为安卓xml的工具类

2592
来自专栏chenssy

【死磕Sharding-jdbc】---结果合并

接下来以执行 SELECT o.*FROM t_order o whereo.user_id=10order byo.order_id desc limit 2...

1133
来自专栏分布式系统进阶

Librdkafka的基础数据结构 2 --- 定时器 原子操作与引用计数

引用了一个新的struct来将引用计数和调用信息结合起来, 使用链表来管理这个struct的对象. 每次对引用计数的操作都要操作这个链表.

911
来自专栏Android知识点总结

Java总结IO篇之File类和Properties类

打开颜色选择器 :读流I-->字符串分割-->字符串存入Map-->使用Map对象还原用户配置 修改配置时 :写流O-->创建Map对象-->字符...

1682

扫码关注云+社区

领取腾讯云代金券