【自学笔记】之LINUX入门的那些破事儿——awk入门

awk编程入门与进阶:从基础到实践
本文从入门级开始介绍awk编程,包括调用方法、记录与域、关系与布尔运算符、表达式、系统变量、格式化输出、内置字符串函数、向awk脚本传递参数、简单的条件语句与循环语句、数组应用等内容,逐步深入到awk的高级用法。

入门第一讲:awk调用方法

awk语句都是由模式(pattern)和动作(action)组成

1.awk三种调用方式整理

①命令行调用

1.新建一个文件input

2.输入2个回车,保存

3.做正则匹配打入如下命令awk'/^$/{print"thisisablankline."}'input

[zhangyongqiao.pt@v128217:~$]catinput

[zhangyongqiao.pt@v128217:~$]awk'/^$/{print"thisisablankline."}'input

thisisablankline.

thisisablankline.

注:模式:/^$/的正则表达式匹配的是空白行

动作:print"thisisablankline."

②脚本间接调用

1.新建文件src.awk输入如下cat到的内容

2.使用awk-f调用src.awk文件

[zhangyongqiao.pt@v128217:~$]catsrc.awk

/^$/{print"thisisablankline."}

[zhangyongqiao.pt@v128217:~$]awk-fsrc.awkinput

thisisablankline.

thisisablankline.

注:这里的awk-fsrc.awk命令段相当于awk'/^$/{print"thisisablankline."}'

③脚本直接调用

1.修改src.awk文件,修改内容参照cat到的部分

2.直接运行./src.awk+待读入文件名

[zhangyongqiao.pt@v128217:~$]catsrc.awk

#!/bin/awk-f #用了那么久,今天终于知道“#!”叫“sha-bang符号”

/^$/{print"thisisablankline."}

[zhangyongqiao.pt@v128217:~$]./src.awkinput

thisisablankline.

thisisablankline.

注:这里的./src.awk命令段相当于awk'/^$/{print"thisisablankline."}'

入门第二讲:记录和域

文件的一行称为一条记录,一条记录的每一个字符串称为一个域,域以空格。TAB及其他符号(,.、等)分割。

例2:记录和域的一些常用方式

首先编辑input文件如下:#小空格为空格键,大空格为TAB

对第一条记录做解释:zhangyi0011989分别为第一条记录对应的4个域

=======================================================

[zhangyongqiao.pt@v128217:~$]catinput

zhangyi0011989

zhanger0021990

zhangsan0031991

========================================================

①利用域操作符$对文件做简单的处理

[zhangyongqiao.pt@v128217:~$]awk'{print$1,$2,$3}'input

zhangyi001

zhanger002

zhangsan003

②配合变量运算表达式对文件处理

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{A=1}{print$(1+A)}'input

yi

er

San

################################################################

这里引入一个关于BEGIN的解释

用法:BEGIN后面跟着的一个表达式在文件读入之前执行一次

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{A=0}{A++}{print$(1+A)}'input

yi #A=1

002 #A=2

1991 #A=3

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{A=0;A++}{print$(1+A)}'input

yi #A=1

er #A=1

san #A=1

第一条命令{A=0}在读入文件之前执行了一次,后面的命令在每行循环时重复执行

第二条命令{A=0;A++}在读入文件之前执行了一次,后面的命令在每行循环时重复执行

注:awk循环原理与sed一样,可以参见上一篇sed入门的最后一部分

################################################################

③使用FS变量改变分隔符

首先对文本进行一点小改动,将所有的空格和TAB换成逗号

[zhangyongqiao.pt@v128217:~$]catinput

zhang,yi,001,1989

zhang,er,002,1990

zhang,an,003,1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{print$2}'input

yi

er

An

****************************************************************

这里大家都知道了$1,$2...的意义了,那么$0又是什么呢?演示一下:

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{print$0}'input

zhang,yi,001,1989

zhang,er,002,1990

zhang,an,003,1991

这下不用解释也知道了吧。$0表示的就是一行记录里面所有的域

****************************************************************

入门第三讲:关系和布尔运算符

讲在前面:

这里就不列举常用布尔运算符了(<>=!=....

2个比较特色的运算符:

1.~匹配正则表达式

2.!~不匹配正则表达式

3.正则表达式与运算符的使用举例

首先看一个系统配置文件~~~~~~~嘿嘿。存密码的哦~

################################################################

[zhangyongqiao.pt@v128217:~$]cat/etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

……

……

……

################################################################

①使用正则表达式~

#第一个域匹配root

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=":"}$1~/root/'/etc/passwd

root:x:0:0:root:/root:/bin/bash

#所有域匹配root

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=":"}$0~/root/'/etc/passwd

root:x:0:0:root:/root:/bin/bash

operator:x:11:0:operator:/root:/sbin/nologin

#所有域不匹配nologin

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=":"}$0~/nologin/'/etc/passwd

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

adm:x:3:4:adm:/var/adm:/sbin/nologin

②使用if语句等

观察文件第三个域与第四个域做如下尝试

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=":"}{if($3==$4)print$0}'/etc/passwd

root:x:0:0:root:/root:/bin/bash

bin:x:1:1:bin:/bin:/sbin/nologin

daemon:x:2:2:daemon:/sbin:/sbin/nologin

nobody:x:99:99:Nobody:/:/sbin/nologin

nscd:x:28:28:NSCDDaemon:/:/sbin/nologin #省略后面的部分

当然,if也可以如其他编程语言规则一样进行多条件匹配

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=":"}{if($3==$4&&$4==0)print$0}'/etc/passwd

root:x:0:0:root:/root:/bin/bash

[zhangyongqiao.pt@v128217:~$]#

注:运算符基本操作就是如此了,其他的就不再特意举例说明

入门第四讲:表达式

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

表达式区别于布尔运算符

所谓表达式最典型的就是(inta+intb=intc的操作

而布尔运算指的是a<b之类的操作,返回值为0或者1

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

4.表达式1

①简单的除法运算

[zhangyongqiao.pt@v128217:~$]catinput

zhang,yi,001,1989

zhang,er,002,1990

zhang,an,003,1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{a=$4;b=a/2;printb}'input

994.5

995

995.5

入门第五讲:系统变量

关于系统变量,这里举出几个例子,详细的表格可以参看一些专门的文档

……………………………………………………………………………………

变量名 意义

$0 记录的所有域

$n 当前记录的第n个域

FILENAME 当前使用的文件名

NF 当前记录中域的数量

NR 当前记录数

……………………………………………………………………………………

5.对如上提到的一些系统变量做实践

[zhangyongqiao.pt@v128217:~$]catinput

zhang,yi,001,1989

zhang,er,002,1990

zhang,an,003,1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{printNF,NR,$0}END{printFILENAME}'input

41zhang,yi,001,1989

42zhang,er,002,1990

43zhang,an,003,1991

入门第六讲:格式化输出

语法规则基本上等同于c语言的printf使用

基本语法如下:

Printf(格式控制符,参数)

###############################################################

所谓的格式控制符也就是(举例说明,不全)

格式符 意义

%c 字符

%s 字符串

%d 整型

%e 浮点数(科学记数)

%f 浮点数

%s 字符串

################################################################

6.基本用法举例

对同一种输出,给出三种不同的命令

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{printf("%s%d",$1,$4)}'input

zhang1989zhang1990zhang1991[zhawk'BEGIN{FS=","}{printf("%s%d\n",$1,$4)}'input

zhang1989

zhang1990

zhang1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{printf("%s\t%d\n",$1,$4)}'input

zhang1989

zhang1990

zhang1991

注:第一条命令在行尾缺少\n,不进行换行,导致第二条命令直接接在第一条命令的输出之后。

那么printfprint的区别何在呢?我们来看下面2行命令的输出

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{printf("%s\t%d\n",$1,$4)}'input

zhang1989

zhang1990

zhang1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{print("%s\t%d\n",$1,$4)}'input

%s%d

zhang1989

%s%d

zhang1990

%s%d

zhang1991

通过输出对比,很容易看出,对于制表符(\t)的处理2者是一样的,但是对于格式符,是printf特有的,在print的基本语法中是不包含这些格式符的。因此他们不能被识别,只能原样输出。

————————————————————————————————

注意:对于第2条命令的246行,

这三行前面都有空格符,这个是怎么回事呢?

看命令行对比:【注意,这里是print,而非printf

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{print("",$1,$4)}'input

zhang1989

zhang1990

zhang1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{print(""$1,$4)}'input

zhang1989

zhang1990

zhang1991

So,在print中,双引号直接被识别成一个字段,这个空格是因为逗号引起的

————————————————————————————————

入门第七讲:内置字符串函数

按照惯例,先列举一些常用的函数

****************************************************************

函数名 意义

gsub(r,s) 在输入文件中s替换r

gsub(r,s,t)在t字符串中用s替换r

index(s,t) 取出t字符串中s所在的位置

length(s) s字符串的长度

match(s,t)t字符串中是否有s

split(r,s,t)在t上将r分成序列s

sub(r,s,t)将t中第一次出现的r替换成s

substr(r,s,t)返回r中从s开始的后缀部分

sbustr(r,s,t) 返回字符串r中从s开始长度为t的后缀部分

***************************************************************

7.关于内置字符串函数的使用

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{printindex("abcdef","a")}'

1

简单的,在abcdef字符串中找到a字符的位置,也就是第一位

注意:这里的indexJAVA中的indexof使用有区别,java中数组下标为0的位为第一位,而这里第一位就是字符串的第一个字符所在的位置。

========================================================

BEGIN的一些强化

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{printindex("abcdef","a")}'

1

[zhangyongqiao.pt@v128217:~$]awk'{printindex("abcdef","a")}'

1

1

从上面2段命令对比可以很显然看到区别,对于BEGIN的定义是在文档读入前进行一次操作。因此不给出文档名,整段print语句也能执行

那么,对于第二条命令,awk命令一直在等待输入一个文档,然后对文档的每一行进行print语句操作。

========================================================

入门第八讲:向awk脚本传递参数

脚本内的变量可以在命令行中进行赋值,实现向awk脚本传递参数

8.在脚本中使用命令行的参数

[zhangyongqiao.pt@v128217:~$]catoutput.awk

#!/bin/awk-f

{print("Thelinenumberis"NR",Defineis"Define"")}

[zhangyongqiao.pt@v128217:~$]./output.awkDefine=3FS=","input

Thelinenumberis1,Defineis3

Thelinenumberis2,Defineis3

Thelinenumberis3,Defineis3

这一段没有特别需要注意的,将脚本语句转到命令行中就很简单了。

以上的操作在命令行中也就是:

[zhangyongqiao.pt@v128217:~$]awk'FS=",",Define=3{print("Thelinenumberis"NR",Defineis"Define"")}'input

Thelinenumberis1,Defineis3

Thelinenumberis2,Defineis3

Thelinenumberis3,Defineis3

一个小问题:希望得到解决

————————————————————————————————

[zhangyongqiao.pt@v128217:~$]awk'Define=3{print("Thelinenumberis"NR",Defineis"Define"")}'input

Thelinenumberis1,Defineis3

Thelinenumberis2,Defineis3

Thelinenumberis3,Defineis3

[zhangyongqiao.pt@v128217:~$]awk'Define=3{print("Thelinenumberis"NR",Defineis"Define"")}FS=","'input

Thelinenumberis1,Defineis3

zhang,yi,001,1989

Thelinenumberis2,Defineis3

zhang,er,002,1990

Thelinenumberis3,Defineis3

zhang,an,003,1991

————————————————————————————————

为什么上面3条类似的命令打印出来的结果却不一样呢?

入门第九讲:简单的条件语句与循环语句

循环和条件语句与一般语言类似,这里就不展开讨论了。给出例9

9.简单的条件判断语句

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{i=1}{if(i==NR){print"Thelinenumberis"NR""}i++}'input

Thelinenumberis1

Thelinenumberis2

Thelinenumberis3

入门第十讲:数组

数组的基本格式:array[index]=value

区别:在awk中,无需定义数组的大小,不像c语言那样,以连续的地址存储。Awk的数组称之为关联数组,类似于key-value的形式,也就是说index的位置可以是小数或者是字符串

9.简单的数组应用

①基本命令

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{data[10.1]="120";;printf("%s\n",data[10.1])}'

120

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{data[10]="120";;printf("%s\n",data[10])}'

120

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{data['a']="120";;printf("%s\n",data['a'])}'

120

上述三个命令很好的解释了awk的数组与一般编程语言中数组的区别。

②判断一个数组元素是否存在的方式

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{data['a']="120";if('a'indata)print"ok"}'

ok

split函数应用

Split(r,s.t)将r字符串以t字符串划分,结果存入s数组中

[zhangyongqiao.pt@v128217:~$]catinput

zhang,yi,001,1989

zhang,er,002,1990

zhang,an,003,1991

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{FS=","}{split($1,name,"n");for(iinname)printname[i]}'input

zha

g

zha

g

zha

g

对于$1也就是字符串“zhang”的操作,以“n”为分隔符,对这个字符串划分,然后打印,分隔符不打印

④数组形式的系统变量

ARGV储存命令行参数,ARGCARGV中参数的个数,下面的命令直观的体现了他们的用法。

[zhangyongqiao.pt@v128217:~$]awk'BEGIN{for(x=0;x<ARGC;x++)printARGV[x];printARGC}'xyzn=99"hello"

awk

xyz

n=99

hello

4

到这里,sed和awk编程的入门就结束了,sed用于刘编辑,将一系列的编辑命令作用于缓冲区中的输入文件的副本,从而实现了对输入文件的各种编辑操作。而awk的一大显著特点是处理结构化文件,所谓的结构化文件,是指划分为记录和与的文件,并且awk提供printf语句能生成格式化报表。

这里分享一本经典的sedawk深入书籍:

O'reilly&Associcates于2000年出版的由ArnoldRobbin编著的sed&awkPocketPeference

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值