NAME

gawk - pattern scanning and processing language

模式扫描和处理语言

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

格式

  1. gawk [options] 'program' FILE ...
  2. program PATTERN{ACTION STATEMENTS}

语句之间用分号分隔

常用选项

  • -F'' :指明输入时用到的字段分隔符,从文件中读取数据时,用什么做分隔符,和内建变量FS一个意思
  • -v var=value :自定义变量
  • -f /path/to/awk_script :将awk调用文件里写好的awk语法进行执行。

表达式

表达式是最简单的语句,大多数其他语句都是由不同类型的表达式组合而成。初等表达式与其他表达式通过运算符组合在一起,形成一个新的表达式。初等表达式是最原始的构造块:它们包括常量、变量、数组引用、函数调用、以及各种内建变量,例如字段的名字。

常量

awk中只有两种常量:字符串和数值,将一个字符序列用一对双引号包围起琰就创建一个字符串常量。所有的数都用浮点格式存储。

变量

用户定义的,内建的,或字段。用户定义的变量名字由数字,字母与下划线构成,但是名字不能以数字开始。所有的内建变量的名字都是大写字母。

每一个变量都有一个值,这个值可以是字符串或数值,或两者都是。因为变量的类型不需要事先声明,所以awk需要根据上下文环境推断出变量的类型。当需要时,awk可以把字符串转化为数值,或反之。

内建变量

变量 意义 默认值
ARGC 命令行参数的个数 -
ARGV 命令行参数数组 -
FILENAME 当前输入文件名 -
FNR 当前输入行的个数 -
FS 控制着输入行的字段分割符 “ ”
NF 记录每行的字段个数 -
NR 到目前为止读到的行的数量 -
OFS 输出字段分割符 “ ”
ORS 输出时的换行符 "\n"
RLENGTH 被函数match匹配的字符串的长度 -
RS 输入时的换行符 "\n"
RSTART 被函数match匹配的字符串的开始
SUBSEP 下标分割符 "\034"

**NF** (number of field)
有时候,必须总是通过\$1,\$2这样的形式引用字段,但是任何表达式都可以出现在\$后面,用来指明一个字段的编号:表达式被求值,求出的值被当作字段的编号。awk计算当前输入行的字段数量,并将它存储在一个内奸的变量中,这个变量叫作`NF`,因此
`{print NF,$1,$NF}`
将会打印:每一行的字段数量,第一个字段,以及最后一个字段
```
[root@node1 ~]# echo "dm ft 12" | awk '{print NF,$1,$NF}'
3 dm 12
[root@node1 ~]# echo "dm ft 12" | awk '{print NF,$1,$NF-1}'
3 dm 11
[root@node1 ~]# echo "dm ft 12" | awk '{print NF,$1,$(NF-1)}'
3 dm ft
```

**NR** (number of record)
`NR`这个变量计算到目前为止,读取到的行的数量。
```
[root@node1 ~]# echo -e "dm ft\nft dm" | awk '{print NR,$0}'
1 dm ft
2 ft dm
```

**FNR**(file record number)
`FNR`表示从当前输入的行数,总共读取的行数。分别在与`NR`的地方是`FNR`对各文件分别计数
```
[root@node2007 ~]# awk -F':' '{print FNR}' /etc/passwd /etc/shadow
1
2
...
20
1
2
...20
[root@node2007 ~]# awk -F':' '{print NR}' /etc/passwd /etc/shadow
1
2
...
40

[root@node1 ~]# awk 'FNR == 1' /etc/passwd

root❌0:0:root:/root:/bin/bash


  1. <br />
  2. **FILENAME**
  3. `FILENAME`表示当前输入文件名

[root@node2007 tmp]# awk 'FILENAME == "/tmp/a.log" {print }' /tmp/*.log

hello

[root@node2007 tmp]# awk '{print FILENAME}' /tmp/a.log /tmp/b.log

/tmp/a.log

/tmp/b.log


  1. <br />
  2. **FS**(input field seperator)
  3. 输入字段分割符,默认为空白字符。

[root@node2007 ~]# echo "root:x" | awk -v FS=':' '{print $1}'

root

[root@node2007 ~]# echo "root:x" | awk -F':' '{print $1}'

root

  1. <br />
  2. **OFS**(output field seperator)
  3. 输出字段分隔符,默认为空白字符。

[root@node2007 ~]# echo "root:x" | awk -v FS=':' -v OFS="|" '{print $1,$2}'

root|x

  1. <br />
  2. **RS**(input record seperator)
  3. 输入时的换行符。默认`\n`

[root@node2007 ~]# echo "Hello World" | awk -v RS=' ' '{print}'

Hello

World

[root@node2007 ~]# echo "Hello World" | awk -v RS='o' '{print}'

Hell

W

rld

  1. <br />
  2. **ORS**(output record seperator)
  3. 输出时的换行符。默认`\n`

[root@node2007 ~]# echo "Hello World" | awk -v ORS='\t' '{print}'

Hello World [root@node2007 ~]# echo "Hello World" | awk -v ORS='#' '{print}'

Hello World#[root@node2007 ~]#

  1. <br />
  2. **ARGC**
  3. 命令行参数的个数。awk命令本身是第一个参数,也就是数组的零下标,之后的常用选项不算做参数,最后提供的参数也是参数。
  4. **ARGV**
  5. 数组,保存的是命令行所给定的各参数
  6. ####内建函数
  7. 内建函数分为`算术函数`和`字符串函数`个人使用算术函数不多,这里只讲`rand`算术函数,剩余都是字符串函数。
  8. **算术函数:**
  9. **rand()**
  10. 返回0和1之间的一个随机数

[root@node2007 ~]# echo | awk '{print rand()*10}' #返回0-10之间的数字

2.37788

  1. <br />
  2. **字符串函数:**
  3. 函数|描述
  4. -|-
  5. index(s,t)|返回字符串t在s中第一次出现的位置,如果t没有出现的话,返回0
  6. length(s)|返回s包含的字符个数
  7. split(s,a)|用`FS`将s分割到数组a中,返回字段的个数
  8. split(s,a,fs)|用`fs`分割s到数组a中,返回字段的个数
  9. sub(r,s)|将\$0的最左最长的,能被r匹配的子字符串替换为s,返回替换发生的次数
  10. sub(r,s,t)|t就是选定区域,然后执行`sbu(r,s)`
  11. substr(s,p)|返回s中从位置p开始的后缀
  12. substr(s,p,n)|返回s中从位置p开始的,长度为n的子字符串
  13. gsub(r,s)|将\$0中所有出现的r替换为s,返回替换发生的次数
  14. gsub(r,s,t)|将字符串t中所有出现r替换为s,返回替换发生的次数
  15. <br />
  16. **index**

[root@node2007 ~]# echo -e "hello\nworld"| awk '{print index($1,"o")}'

5

2

[root@node2007 ~]# echo -e "hello\nworld"| awk '{print index($1,"a")}'

0

0

  1. <br />
  2. **length**

[root@node2007 ~]# echo -e "hello\nworldd"| awk '{print length($1)}'

5

6

  1. <br />
  2. **split**

[root@node2007 ~]# echo -e "/etc/nginx/nginx.conf"| awk '{split($0,a,"/");for(i=1;i<=length(a);i++){if (a[i] == ""){countine}else{print a[i]}}}' #语法格式后面会详细介绍

etc

nginx

nginx.conf

  1. <br />
  2. **sub,gsub**
  3. `sub`和`gsub`相当于`sed`命令替换命令后带`g`参数的效果。
  4. 匹配指定域/记录中最大、最靠左边的子字符串的正则表达式,并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候。

[root@node2007 ~]# echo -e "hello"| awk '{print $0,sub("l","L"),$0}'

hello 1 heLlo

[root@node2007 ~]# echo -e "hello world"| awk '{print $0,sub(/l+/,"L",$2),$0}'

hello world 1 hello worLd

[root@node2007 ~]# echo -e "hello world"| awk '{gsub(/l+/,"L");print}'

heLo worLd

[root@node2007 ~]# echo -e "hello world"| awk '{gsub(/l+/,"L",$2);print}'

hello worLd


  1. <br />
  2. **substr**

[root@node2007 ~]# echo -e "/etc/nginx/nginx.conf"| awk -v FS='/' '{print substr($NF,1)}' #给定一个位置,然后将后缀输出

nginx.conf

[root@node2007 ~]# echo -e "/etc/nginx/nginx.conf"| awk -v FS='/' '{print substr($NF,1,5)}' #限定输出长度

nginx

  1. <br />
  2. ####字段变量
  3. 当前输入行的字段从\$1,\$2,一直到\$NF;\$0表示整行。字段变量与其他变量相比没什么不同,也可以用在算术或字符串运算中,也可以被赋值。

[root@node2007 ~]# echo "hello" | awk '{$1 = "world";print}'

world

[root@node2007 ~]# echo "10" | awk '{$1 = $1 / 2;print $1}'

5

  1. <br />
  2. ###PATTERN(模式)
  3. ####BEGIN&END
  4. `BEGIN`与`END`这两个模式不匹配任何输入行,实际情况是,当awk从输入读取数据之前,`BEGIN`的语句开始执行;当所有输入数据被读取完毕,`END`语句开始执行。于是,`BEGIN`和`END`分别提供了一种控制初始化与扫尾的方式。
  5. `BEGIN`的一个常用用途是更改输入行被分割为字段的默认方式。使用内键变量`FS`和常用选项`-F`

[root@node1 tmp]# cat countries

USSR 8649 275 Asia

Canada 3852 25 North America

China 3705 1032 Asia

USA 3615 237 North America

[root@node1 tmp]# awk 'BEGIN{FS="\t"

printf("%10s%6s%5s %s\n\n",

"country","area","pop","continent")

}

{ printf("%10s %6d %5d %s\n",$1,$2,$3,$4)

area = area + $2

pop = pop + $3

}

END{printf("\n%10s %6d %5d\n","TOTAL",area,pop)}' countries

country area pop continent

  1. USSR 8649 275 Asia
  2. Canada 3852 25 North America
  3. China 3705 1032 Asia
  4. USA 3615 237 North America
  5. TOTAL 19821 1569
  1. <br />
  2. ####relational expression
  3. `relational expression{action}`表示每碰到一个使`relational expression`为真的输入行,`{action}`就执行。为真:指的是其值非零或非空。这里的`relational expression`其实就是使用操作符来做判断,并根据判断结果来确定是否要执行`{action}`。

[root@node2007 tmp]# awk -F':' '$3 == 0{print}' /etc/passwd

root❌0:0:root:/root:/bin/bash


  1. * `relational expression`是表达式:
  2. - 比较操作符:`>,<,>=,<=,!=,==,~(匹配),!~(不匹配)`
  3. - 算术操作符:`+,-,*,/,^(指数运算),%`
  4. - 赋值操作符:`=,+=,-=,/=,%=,^=,++,--`
  5. - 模式匹配符:`||,&&,!(使用时最好将所需取反用小括号括起来)`
  6. <br />
  7. ####/regular expression/
  8. `/regular expression/{action}`仅处理能够被此处模式匹配到的行。此处的`regular`即可使用`regex`(正则表达式)来做匹配

[root@node2007 tmp]# awk -F':' '$1 ~ /oot>/{print}' /etc/passwd #只要$1包含oot结尾的单词即为真

root❌0:0:root:/root:/bin/bash

[root@node2007 tmp]# awk -F':' '$1 ~ /o*t>/{print $1}' /etc/passwd #这里的的o*匹配的是零个o或者任意个o,与glob语法中的*请区分下

root

halt

  1. <br />
  2. ####line ranges
  3. `/part1/,/part2/`匹配一个或多个输入行,这些输入行从匹配part1的行开始,到匹配part2的行结束,包括这两行;part1可以与part2匹配到同一行。`part`匹配也可使用正则表达式。
  4. **注:不支持直接给出数字,但可以使用内键变量`FNR`来代替直接给出数字。**

[root@node2007 tmp]# echo -e "1\n2\n1\n3\n2\n3" | awk '/1/,/3/{print}' #这里可以看出只匹配第一个

1

2

1

3

[root@node2007 tmp]# echo -e "1\n2\n1\n3\n2\n3" | awk 'FNR == 3 {print}'

1

[root@node2007 tmp]# echo -e "1\n2\n1\n3\n2\n3" | awk 'FNR <= 3 {print}'

1

2

1

  1. <br />
  2. ####模式总结:
  3. 模式|例子|匹配
  4. -|-|-
  5. BEGIN|BEGIN|输入被读取之前
  6. END|END|所有输入被读取完之后
  7. expression|$3 < 100|第3个字段小于100的行
  8. string-matching| $2 ~ /Asia/|第2字段含有Asia的行
  9. compound|\$3 < 100 && \$2 ~ /Asia/|第3个字段小于100并且第2字段含有Asia的行
  10. range|NR==10,/^root\>/|第10行到行首第一个单词是root的之间的行。
  11. **额外使用技巧:**
  12. 正则表达式可以不用包围在两个斜杠中,可以将正则表达式赋值给一个变量,然后使用该变量匹配数据。

BEGIN { digits = "[1]+$" }

$2 ~ digits

  1. <br />
  2. ###流程控制语句
  3. > awk提供有用于决策`if-else`语句,以及循环语句,它们只能用在动作(action)里。所有的这些都来源于C语言,如果你熟悉C语言,我相信下面的语法对你来说小菜一碟。
  4. > awk 提供花括号用于语句组合,`if-else`用于决策,`while`,`for`,`do`语句用于循环。一条单独的语句总是可以被替换为一个被花括号包围起来的语句列表,列表中的语句用换行符或分号分开,换行符可以出现在任何左花括号之后,也可心出现在任何右花括号之前。

流程控制语句:

if (expression) statements

if (expression) statements1 else statements2

while (expression) statements

for (variable in array) statements

do statements while (expression) #执行statements,如果为expression为真就重复

状态控制

break #退出循环

continue #退出当前循环

next #开始输入主循环的下一次迭代,BEGIN后算主循环

exit #执行END动作;如果已经在END动作内,那就退出程序,将expression作为程序退出状态返回

  1. <br />
  2. ####if
  3. 语法格式:

PATTERN {

if (condition)

{

action

....

}

else

action

}

if-else可以缩写成如下格式:

selector?if-true-expression:if-false-expression

#if-else-if

PATTERN {

if (condition1)

{

action1

}

else if (condition2)

{

action2

}

...

else

action

}


  1. 示例:

[root@node2007 ~]# echo "1 2 3" | awk '{if ($1 == 1){print "\$1 equal 1"}}'

$1 equal 1

[root@node2007 ~]# echo "1 2 3" | awk '{if ($1 != 1){print "\$1 equal 1"}else{print "other is 2 3"}}'

other is 2 3

[root@node2007 ~]# echo "1 2 3" | awk '{if ($1 != 1){print "\$1 equal 1"}else if ($2 == 2){print "\$2 equal 2"}}'

$2 equal 2


  1. <br />
  2. ####for
  3. C语言的for语句,这里不做解释。

PATTERN {

for (i=1;i<=10;++i){

action

...

}

}

无限循环

PATTERN {

for (;

awk - 数据分析和展示的更多相关文章

  1. 数据分析与展示——NumPy库入门

    这是我学习北京理工大学嵩天老师的<Python数据分析与展示>课程的笔记.嵩老师的课程重点突出.层次分明,在这里特别感谢嵩老师的精彩讲解. NumPy库入门 数据的维度 维度是一组数据的组 ...

  2. 【学习笔记】PYTHON数据分析与展示(北理工 嵩天)

    0 数据分析之前奏 课程主要内容:常用IDE:本课程主要使用:Anaconda Anaconda:一个集合,包括conda.某版本Python.一批第三方库等 -支持近800个第三方库 -适合科学计算 ...

  3. python数据分析及展示(一)

    一.IDE选择 Anaconda软件:开源免费,https://www.anaconda.com下载,根据系统进行安装.由于下载速度慢,可以去清华大学开源软件镜像站下载. Spyder软件设置:Too ...

  4. 数据分析与展示---Pandas库数据特征分析

    说明:0轴axis=0和1轴axis=1 简介 一:数据的排序 二:数据的基本统计分析 三:数据的累积统计分析 四:数据的相关分析 一:数据的排序 a b c d a b c d 二:数据的基本统计分 ...

  5. 数据分析与展示---Matplotlib基本绘图函数

    一:基本绘图函数(这里介绍16个,还有许多其他的) 二:pyplot饼图plt.pie的绘制 三:pyplot直方图plt.hist的绘制 (一)修改第二个参数bins:代表直方图的个数,均分为多段, ...

  6. pyecharts数据分析及展示

    仅仅从网上爬下数据当然是不够用的,主要还得对数据进行分析与展示,大部分人都看重薪资,但是薪资数据有的是*k/月,有的是*万/月,还有*万/年等等,就要对数据进行清理 将所有单位统一化,全部换算成统一单 ...

  7. Python数据分析与展示(1)-数据分析之表示(1)-NumPy库入门

    Numpy库入门 从一个数据到一组数据 维度:一组数据的组织形式 一维数据:由对等关系的有序或无序数据构成,采用线性方式组织. 可用类型:对应列表.数组和集合 不同点: 列表:数据类型可以不同 数组: ...

  8. 数据分析与展示——Pandas数据特征分析

    Pandas数据特征分析 数据的排序 将一组数据通过摘要(有损地提取数据特征的过程)的方式,可以获得基本统计(含排序).分布/累计统计.数据特征(相关性.周期性等).数据挖掘(形成知识). .sort ...

  9. 数据分析与展示——Matplotlib基础绘图函数示例

    Matplotlib库入门 Matplotlib基础绘图函数示例 pyplot基础图表函数概述 函数 说明 plt.plot(x,y,fmt, ...) 绘制一个坐标图 plt.boxplot(dat ...

随机推荐

  1. Kaggle实战——点击率预估

    https://blog.csdn.net/chengcheng1394/article/details/78940565 原创文章,转载请注明出处: http://blog.csdn.net/che ...

  2. python client.py

    vi /Library/Frameworks/Python.framework/Versions//http/client.py vi /Library/Frameworks/Python.frame ...

  3. 依赖注入之unity(winform方式)

    依赖注入之unity(winform方式) 要讲unity就必须先了解DI和IOC及DIP,如下链接提供DI和IOC的基础:https://www.cnblogs.com/zlp520/p/12015 ...

  4. 深度学习 NI-DL 框架

    NI-DL 应用框架:图像分类,目标检测,分割提取. 底层:TensorFlow,Keras,Cuda,C/C++ 上层:C#.NET Winform [图像分类] 识别一张图片是否为某个类型的物体/ ...

  5. Python【每日一问】19

    问: [基础题]:请解释类方法.静态方法.属性方法[提高题]:有以下几个数字:1.2.3.4.5,能组成多少个互不相同且无重复数字的三位数?都是多少?(代码实现) 答: [基础题]:请解释类方法.静态 ...

  6. AQS1---走向稳定态

    AQS的思想(稳定思想):即使确定了正常节点,这个节点也可能下一秒异常,即使找到了正常节点,这个节点可能只是异常status=0/-1的节点,这些都不要紧,都只是在自己旋转‘生命周期’里面和自己所看到 ...

  7. java小程序---简陋版多人聊天室

    功能需求: 1 每运行一次主函数,创建一个客户端聊天界面; 2 客户端界面分三块,公屏(显示所有客户端发送的信息),私屏(用于输入个人想要发送的信息),发送按钮(点击一次,将客户端信息发送到服务端) ...

  8. Java笔记_web.xml文件

    在JavaEE工程中,web.xml文件是用来初始化配置信息:比如Welcome页面.servlet.servlet-mapping.filter.listener.启动加载级别等,但并不是必须的,一 ...

  9. ORA-01779: 无法修改与非键值保存表对应的列

    项目中通过子查询更新数据时遇到ORA-01779: 无法修改与非键值保存表对应的列,模拟过程如下: 1.创建测试表 CREATE TABLE tt1 (ID INT,col1 VARCHAR2()); ...

  10. C# 单向链表 逆序(递归)

    static void Main(string[] args) { while (true) { LinkedList L = new LinkedList(); L.Add(new Node(&qu ...