awk (三剑客之一)

Linux处理文本工具:

grep:过滤文本内容 

sed:编辑文本内容 

awk 


awk:Aho,Kernighan and Weinberger

报告生成器,以特定的条件查找文本内容,再以特定的格式显示出来


nawk:Solaris

gawk: Linux

# ls -l /bin/awk 

lrwxrwxrwx. 1 root root 4 7月  30 2014 /bin/awk -> gawk



awk命令的格式:

# awk [options] 'script' file1 file2 ...

# awk [options] 'PATTERN{action}' file1 file2 ...


PATTERN:

用文本字符与正则表达式元字符描述的条件 

action:

print

prinf:必须指定输出格式


options:

-F:指定文本分割符


awk处理文本机制:

awk将符合PATTERN的文本逐行取出,并按照指定的分割符(默认为空白,通过-F选项可以指定分割符)进行分割,然后将分割后的每段按照特定的格式输出 




awk的输出:


一、print

print的使用格式:

print item1,item2,....

注意:

1、各项目间使用逗号分隔开,而输出时以空白字符作为分隔

2、输出的item可以为字符串、数值、当前的记录的字段($1)、变量或者awk的表达式;数值会先转换成字符串,然后输出

3、print命令后面的item可以省略,此时其功能相当于print $0($0代表未分割的整行文本内容),因此,如果想输出空白行,则需要使用print "";



以空白分割,显示文本中的第1段及第2段内容

# awk '{print $1,$2}' test.txt 

this is


输出时可以指定要输出的内容,例如hello world,需要使用双引号引起来

# awk '{print $1,"hello world",$2}' test.txt 

this hello world is


BEGIN{OFS="%"},指定显示每段内容时的分割符(默认以空白为分割)


以%作为分割符,显示第1段及第4段的内容

# awk 'BEGIN{OFS="%"}{print $1,$4}' test.txt 

this%test.


示例:

输出3行内容

# awk 'BEGIN{print "line one\nline two\nline three"}'

line one

line two

line three


输出/etc/passwd中的用户名及其uid

# awk -F: '{print $1,$3}' /etc/passwd 




awk变量


1、awk内置变量之记录变量

FS: 指定读取文本时,所使用的段分隔符,默认为空白字符;相当于awk的-F选项 

OFS:指定输出的分隔符,默认为空白字符;

RS: 指定读取文本时,所使用的换行符(指定以什么字符作为换行符);默认为换行符

ORS:指定输出时所使用的行分隔符



2、awk内置变量之数据变量

NR:记录awk所处理的文本的行数,如果有多个文件,所有文件统一进行计数

# awk '{print NR}' test.txt 1.txt 

1

2

3

4

结果1用于记录test.txt行数,2,3,4是1.txt文件的行数


注意:

print在显示变量值时,不需要使用$



FNR:记录awk正在处理的文件的行数,如果有多个文件,每个文件分别进行计数

# awk '{print FNR}' test.txt 1.txt 

1

1

2

3

结果1是test.txt文件的行数,1.txt的行数从1开始再进行单独计数



NF:记录awk正在处理的当前行被分隔成了几个字段

# cat test.txt 

this is a test.

# awk '{print NF}' test.txt 

4

# awk '{print $NF}' test.txt 

test.



3、用户自定义的变量

awk允许用户自定义变量,变量名称不能以数字开头,且区分大小写


示例:

定义变量test,值为hello awk 

方法1:使用-v选项

# awk -v test="hello awk" 'BEGIN{print test}'

hello awk


方法2:在BEGIN{}模式中定义变量

# awk 'BEGIN{test="hello awk";print test}'

hello awk

注意:

awk在练习时,如果后面不跟文件作为参数,通过要使用BEGIN{}

{}中test="hello awk"和print test是两个语句,如果{}有多个语句,需要使用;号隔开




二、printf,格式化输出内容

格式:

printf format,item1,item2,...


要点:

1、printf输出时要指定格式format

2、format用于指定后面的每个item输出的格式

3、printf语句不会自动打印换行符\n 


format:

%c:显示单个字符

%d,%i:十进制整数

%e,%E:科学计数法显示数值

%f:显示浮点数

%g,%G:以科学计数法的格式或浮点数的格式显示数值

%s:显示字符串

%u:无符号整数

%%:显示%自身


修饰符:

N:显示宽度,N为数字

-:左对齐,默认为右对齐

+:显示数值符号


显示第1个字符t,默认不会换行,如果想要换行,需要使用\n 

# awk '{printf "%c",$1}' test.txt 

t

# awk '{printf "%c\n",$1}' test.txt 

t


显示字符串 

# awk '{printf "%s\n",$1}' test.txt 

this


以10个字符的宽度显示字符串,右对齐输出

# awk '{printf "%10s\n",$1}' test.txt 

      this


左对齐显示10个字符串

# awk '{printf "%-10s\n",$1}' test.txt 

this(此处后续有6个空格)      


分别指定显示$1和$3字段的格式

# awk '{printf "%-10s,%-10s\n",$1,$3}' test.txt 

this      ,a         


以十进制的格式显示用户的uid

# awk -F: '{printf "%-5d\n",$3}' /etc/passwd

0    

1    

2    



awk的操作符

1、算术操作符

-x 负值

+x 转换为数值,正值

x^y,x**y  次方 

x*y

x/y

x+y

x-y

x%y


2、字符串操作符

+:实现字符串连接


3、赋值操作符

=

+=

-=

*=

/=

%=

^=

**=

  

 

++

--


需要注意的是,如果某模式为=号,此时使用/=/可能会有语法错误,应以/[=]/替换


4、比较操作符

x < y

x <= y

x > y

x >= y

x == y

x != y

x ~ y:x为字符串,y为模式,如果x可以被模式匹配则为真,否则为假

x !~ y

subscript in array :数组中有subscript下标为真


5、逻辑关系符

&&

||


6、条件表达式

condition?if-true-exp:if-false-exp

condition为真,则执行if-true-exp,否则执行if-false-exp 

7、函数调用 

function_name(argu1,argu2)







# awk [options] 'PATTERN{action}' file1 file2 ...


PATTERN表示方法:


1、正则表达式,格式为/regex/

以冒号为分隔符,显示/etc/passwd以r开头的行的第1段

# awk -F: '/^r/{print $1}' /etc/passwd

root

rpc

rtkit

rpcuser


2、表达式,由上述操作符组成的表达式


显示uid大于等于500的用户名及uid 

# awk -F: '$3>=500{print $1,$3}' /etc/passwd

nfsnobody 65534

wjc 500


显示默认shell为/bin/bash的用户名及shell名称

# awk -F: '$7=="/bin/bash"{print $1,$7}' /etc/passwd

# awk -F: '$7 ~ "bash$"{print $1,$7}' /etc/passwd

root /bin/bash

mysql /bin/bash

wjc /bin/bash


3、指定范围,格式为pattern1,pattern2

以冒号为分隔符,显示uid=0到最后一个字段为nologin结尾中间所有行的用户名,uid及shell

# awk -F: '$3==0,$7 ~ "nologin$"{print $1,$3,$7}' /etc/passwd

root 0 /bin/bash

bin 1 /sbin/nologin


格式化输出样例

# awk -F: '$3==0,$7 ~ "nologin$"{printf "%-10s%-10s%-20s\n",$1,$3,$7}' /etc/passwd

root      0         /bin/bash           

bin       1         /sbin/nologin   


4、BEGIN/END,特殊模式

BEGIN表示awk进行处理前执行一次操作

END表示awk处理完最后一行结束前执行一次操作


使用BEGIN打印表头

# awk -F: 'BEGIN{printf "%-10s%-10s%-20s\n","Username","Uid","Shell"}$3==0,$7 ~ "nologin$"{printf "%-10s%-10s%-10s\n",$1,$3,$7}' /etc/passwd

Username  Uid       Shell               

root      0         /bin/bash 

bin       1         /sbin/nologin


使用END打印表尾

# awk -F: 'BEGIN{printf "%-10s%-10s%-20s\n","Username","Uid","Shell"}$3==0,$7 ~ "nologin$"{printf "%-10s%-10s%-10s\n",$1,$3,$7}END{print "END OF File..."}' /etc/passwd

Username  Uid       Shell               

root      0         /bin/bash 

bin       1         /sbin/nologin

END OF File...




常见的action:

1、表达式

2、控制语句(if,case,while,do...while,for)

3、复合语句

4、输入语句

5、输出语句 



控制语句

1、if...else 

格式:

if (condition) {statement} else {statement}

如果statement只有一条语句,{}可以不写


以冒号为分隔符,判断第1个字段,如果为root,则显示用户名 Admin,否则显示用户名 Common User

# awk -F: '{if ($1=="root") print $1,"Admin";else print $1,"Common User"}' /etc/passwd

root Admin

bin Common User

daemon Common User

adm Common User

lp Common User

sync Common User

shutdown Common User

格式化输出 

# awk -F: '{if ($1=="root") printf "%-15s: %-15s\n",$1,"Admin";else printf "%-15s: %-15s\n",$1,"Common User"}' /etc/passwd

root           : Admin          

bin            : Common User    

daemon         : Common User    

adm            : Common User    

lp             : Common User    

sync           : Common User    

shutdown       : Common User    

halt           : Common User    


统计uid大于50的用户个数

# awk -F: -v sum=0 '{if ($3>50) sum++}END{print "The number of user: ",sum}' /etc/passwd

The number of user:  16


取出磁盘使用率大于5%的

# df -h | awk '{if ($5>5) print $0}'

文件系统      容量  已用  可用 已用%% 挂载点

/dev/sda3              97G  3.8G   88G   5% /

/dev/sda1             194M   27M  158M  15% /boot

/dev/sr0              2.9G  2.9G     0 100% /mnt




2、while,循环每一行的每一个字段

格式:

while (condition) {statement1;statement2;....}


以冒号为分隔符,显示/etc/passwd每一行的前3个字段

# awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd


以冒号为分隔符,判断每一行的每一个字段的长度如果大于4,则显示之

# awk -F: '{i=1;while (i<=NF) {if (length($i)>=4) {print $i};i++}}' /etc/passwd





3、do...while 

格式:

do {statement1;statement2;...} while(condition)

以冒号为分隔符,显示/etc/passwd每一行的前3个字段

# awk -F: '{i=1;do {print $i;i++} while (i<=3)}' /etc/passwd

root

x

0

bin

x

1



4、for

格式:

for (variable assignment; condition; iteration process) {statement1;statement2;...}

以冒号为分隔符,显示/etc/passwd每一行的前3个字段

# awk -F: '{for (i=1;i<=3;i++) {print $i}}' /etc/passwd

root

x

0

bin

x

1


5、switch...case 

格式:

switch (expression) {case value1:statement1;statement2;... case value2:statement1;statement2;... default:statement1;statement2;...}


6、break continue

用于中断循环


7、next

提前结束对本行文本的处理,并继续处理下一行;

显示uid为奇数的用户

# awk -F: 'BEGIN{printf "%-10s%-10s\n","Username","Uid"}{if ($3%2==0) next;else printf "%-10s%-10s\n",$1,$3}' /etc/passwd

Username  Uid       

bin       1         

adm       3         

sync      5         

halt      7    




awk中使用数组


数组 

array[index-expression]


数组下标从1开始,也可以使用字符串作为数组下标


index-expression可以使用任意字符串。需要注意的是,如果某数组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为0;因此,要判断某数组中是否存在某元素,需要使用index in array的方式


要遍历数组中每一个元素,需要使用如下的特殊结构:

for (var in array){statement1;statement2;...}

其中,var是数组下标


统计每个shell的使用个数

# awk -F: '{shell[$NF]++}END{for(A in shell) {print A,shell[A]}}' /etc/passwd

/bin/sync 1

/bin/bash 3

/sbin/nologin 31

/sbin/halt 1

/sbin/shutdown 1


{shell[$NF]}:以每行的最后的shell名称为下标,为数组元素shell[$NF]赋初始值1,如果遇到相同的shell,则该值递增1

A:代表数组的下标

print A:显示数组下标

print shell[A]:显示此下标对应的数组值,也就是个数



统计每个状态的tcp连接的个数

# netstat -ant | sed '1,2d' | awk '{array[$NF]++}END{for(A in array) {print A,array[A]}}'

LISTEN 13

ESTABLISHED 1


或者

# netstat -ant | awk '/^tcp/{state[$NF]++}END{for(A in state) {print A,state[A]}}' 

LISTEN 13

ESTABLISHED 1



统计/var/log/httpd/access_log每个IP的访问次数

# awk '{count[$1]++}END{for(ip in count) {print ip,count[ip]}}' /var/log/httpd/access_log 

10.1.1.100 53


格式化输出:

# awk 'BEGIN{printf "%-20s%-20s\n","IP Address","Access Count"}{count[$1]++}END{for(ip in count) {printf "%-20s%-20s\n",ip,count[ip]}}' /var/log/httpd/access_log 

IP Address          Access Count        

10.1.1.100          53     









awk的内置函数


split(string,array [,filedsep [,seps]])

将string表示的字符串以fileldsep为分隔符进行分割,并将分隔后的结果保存至数据array中;数组下标从0开始


length(string)

返回string字符串的字符个数


substr(string,start [,length])

取string字符串中的子串,从start开始,取length个;start从1开始计数


system(command)

执行系统command并将结果返回给awk命令


systime()

返回系统当前时间


tolower(string)

将string中的所有字母转为小写


toupper(string)

将string中所有字母转换为大写


你可能感兴趣的:(action,表达式,三剑客)