NAME

gawk - pattern scanning and processing language

模式扫描和处理语言

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

格式

gawk [options] 'program' FILE ...
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


<br />
**FILENAME**
`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


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

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

root

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

root

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

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

root|x

<br />
**RS**(input record seperator)
输入时的换行符。默认`\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

<br />
**ORS**(output record seperator)
输出时的换行符。默认`\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 ~]#

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

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

2.37788

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

<br />
**length**

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

5

6

<br />
**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

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

[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


<br />
**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

<br />

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

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

world

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

5

<br />

###PATTERN(模式)
####BEGIN&END
`BEGIN`与`END`这两个模式不匹配任何输入行,实际情况是,当awk从输入读取数据之前,`BEGIN`的语句开始执行;当所有输入数据被读取完毕,`END`语句开始执行。于是,`BEGIN`和`END`分别提供了一种控制初始化与扫尾的方式。
`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

  USSR   8649   275    Asia
Canada 3852 25 North America
China 3705 1032 Asia
USA 3615 237 North America TOTAL 19821 1569
<br />
####relational expression
`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


* `relational expression`是表达式:
- 比较操作符:`>,<,>=,<=,!=,==,~(匹配),!~(不匹配)`
- 算术操作符:`+,-,*,/,^(指数运算),%`
- 赋值操作符:`=,+=,-=,/=,%=,^=,++,--`
- 模式匹配符:`||,&&,!(使用时最好将所需取反用小括号括起来)` <br />
####/regular expression/
`/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

<br />

####line ranges
`/part1/,/part2/`匹配一个或多个输入行,这些输入行从匹配part1的行开始,到匹配part2的行结束,包括这两行;part1可以与part2匹配到同一行。`part`匹配也可使用正则表达式。
**注:不支持直接给出数字,但可以使用内键变量`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

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

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

$2 ~ digits



<br />

###流程控制语句
> awk提供有用于决策`if-else`语句,以及循环语句,它们只能用在动作(action)里。所有的这些都来源于C语言,如果你熟悉C语言,我相信下面的语法对你来说小菜一碟。
> 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作为程序退出状态返回

<br />
####if
语法格式:

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

}


示例:

[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


<br />
####for
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. ZROI 暑期高端峰会 A班 Day1 序列数据结构

    FBI Warning:本文包含大量人类的本质之一 CF643G 维护一个序列,可以区间赋值,求区间中出现超过 \(p\%\) 的数. 允许输出不对的数,允许重复输出,但是所有对的数都一定要输出.而且 ...

  2. Js中的排他思想

    <body>     <button>按钮1</button>     <button>按钮2</button>     <butto ...

  3. nlp语义理解的一点儿看法

    nlp领域里,语义理解仍然是难题! 给你一篇文章或者一个句子,人们在理解这些句子时,头脑中会进行上下文的搜索和知识联想.通常情况下,人在理解语义时头脑中会搜寻与之相关的知识.知识图谱的创始人人为,构成 ...

  4. MongoDB Shell 命令

    更新列名 db.Stores.update({}, {$rename : {"StoreId" : "MetaId"}}, false, true) 查询长度 ...

  5. Java实现AES加密(window机器和linux机器) 注意window机器 和linux机器算法稍有不同

    一)什么是AES? 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),是一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用. ...

  6. 重启nova-scheduler服务,报错Login was refused using authentication mechanism AMQPLAIN

    问题描述 运行 systemctl restart openstack-nova-scheduler.service 失败,查看日志报错如下: 2019-12-22 14:52:27.426 1513 ...

  7. 【K8S】helm chart多环境部署最佳实践-示例

    Chart.yaml apiVersion: v1 appVersion: "1.0" description: A Helm chart for Kubernetes name: ...

  8. 【06月05日】A股滚动市净率PB历史新低排名

    2010年01月01日 到 2019年06月05日 之间,滚动市净率历史新低排名. 上市三年以上的公司,2019年06月05日市净率在30以下的公司. 来源:A股滚动市净率(PB)历史新低排名. 1 ...

  9. ASP.NET Core使用Docker-Compose实现多容器应用部署

    一.需求背景 人生苦短,我用.NET Core!前面的<ASP.NET Core使用Docker进行容器化托管和部署>基础课程我们学习了如何使用Docker来部署搭建ASP.NET Cor ...

  10. 小白的C++之路——求质数

    初学C++,打算用博客记录学习的足迹.写了两个求质数的程序,修修改改. #include <iostream> #include <math.h> using namespac ...