入门第一讲: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:~$]#
注:运算符基本操作就是如此了,其他的就不再特意举例说明
入门第四讲:表达式
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
表达式区别于布尔运算符
所谓表达式最典型的就是(int)a+(int)b=(int)c的操作
而布尔运算指的是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,不进行换行,导致第二条命令直接接在第一条命令的输出之后。
那么printf与print的区别何在呢?我们来看下面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条命令的2,4,6行,
这三行前面都有空格符,这个是怎么回事呢?
看命令行对比:【注意,这里是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字符的位置,也就是第一位
注意:这里的index与JAVA中的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储存命令行参数,ARGC为ARGV中参数的个数,下面的命令直观的体现了他们的用法。
[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语句能生成格式化报表。
这里分享一本经典的sed与awk深入书籍:
O'reilly&Associcates于2000年出版的由ArnoldRobbin编著的sed&awkPocketPeference
awk编程入门与进阶:从基础到实践
本文从入门级开始介绍awk编程,包括调用方法、记录与域、关系与布尔运算符、表达式、系统变量、格式化输出、内置字符串函数、向awk脚本传递参数、简单的条件语句与循环语句、数组应用等内容,逐步深入到awk的高级用法。
942

被折叠的 条评论
为什么被折叠?



