码迷,mamicode.com
首页 > 其他好文 > 详细

awk(未完)

时间:2015-05-25 06:19:16      阅读:117      评论:0      收藏:0      [点我收藏+]

标签:awk

awk的运行方式

(1)  awk命令行

(2)  awk程序文件

awk f /path/from/awk_script

(3)  awk脚本

#!/bin/awk f

基本用法:

    gawk[OPTIONS] program FILE1 FILE2……

         program:PATTERN{ACTIONSTATEMENT}

选项:

-F[]:指明输入字段分隔符

-vVAR_NAME=VALUE:变量赋值

-f /PATH/FROM/AWK_SCRIPT:

1、awk的输出命令之一:print

用法:print item1,item2,……

   item:

      字符串:用引号引用

      变量:显示变量的值

           引用变量:直接使用变量名

       数值:无需加引号

示例:字符串输出,向系统中用户问好

[root@localhost ~]# awk -F: ‘{print"hello",$1}‘ /etc/passwd
hello root
hello bin
hello daemon
hello adm

变量输出:

显示变量:定义变量为f1,值为1,然后输出f1就会输出变量的值也就是1

[root@localhost ~]# awk -F: -v f1=1 ‘{print f1}‘/etc/passwd
1
1
1
1

引用变量:使用$引用变量,就相当于输出$1,也就是第一段的内容

[root@localhost ~]# awk -F: -v f1=1 ‘{print $f1}‘ /etc/passwd
root
bin
daemon
adm

输出数值:

[root@localhost ~]# awk ‘{print 123}‘ /etc/passwd
123
123

 

要点:

(1)  各item直接需要使用逗号分割;而输出时的分隔符为默认空白字符;

示例:没有使用逗号,就会将两个值接连在一起

[root@localhost ~]# awk ‘{print "hello""world"}‘ /etc/passwd
helloworld
helloworld
helloworld

(2)  输出的各item可以为字符串或数值、当前记录的字段($#)、变量或awk的表达式;数值会被隐式转换为字符串进行输出

(3)  print后面的item省略时,相当于允许print $0,用于输出整行

(4)  输出空白字符:print


2、变量

2.1内置变量


FS:输入字段分隔符,默认为空白

        -v FS=[ ,:.]   #指定多个分隔符 

示例:指定FS的值为,分割符也就成为了。效果和-F:一样

[root@localhost ~]# awk -v FS=":" ‘{print$1,$3}‘ /etc/passwd
root 0
bin 1
daemon 2

指定多个分隔符:输出awk.txt文件的第三字段,但是第三字段的分割符分别是空白字符和逗号,这时可以将FS赋值为空白和逗号。

[root@localhost ~]# cat awk.txt
This is the firsh line.
Here you are.
This is tomas,jason.
[root@localhost ~]# awk -v FS="[ ,]"‘{print $3}‘ awk.txt
the
are.
tomas


 RS:输入时的行分隔符,默认为换行符

示例:指定行分割符为空白字符,那么出现空白字符就会换号。

[root@localhost ~]# awk -v RS=" " ‘{print$0}‘ awk.txt
This
is
the
firsh
line.
Here
you
are.
This
is
tomas,jason.

 

 OFS:输出时的字段分隔符,默认为空白

示例:指定输出时字段分隔符为

[root@localhost ~]# awk -v FS=":" -v OFS=":" ‘{print $1,$3,$7}‘ /etc/passwd
root:0:/bin/bash
bin:1:/sbin/nologin
daemon:2:/sbin/nologin


 ORS:输出时的行分隔符,默认为换行符

[root@localhost ~]# awk -v RS=" " -v ORS=" " ‘{print $0}‘ awk.txt
This is the firsh line.
Here you are.
This is tomas,jason.
 
[root@localhost ~]# awk -v ORS=" "‘{print $0}‘ awk.txt
This is the firsh line. Here you are. This istomas,jason.


NF:当前行的字段数

示例:显示每一行的字段数

[root@localhost ~]# awk ‘{print NF}‘ awk.txt
5
3
3

显示最后一个字段

[root@localhost ~]# awk ‘{print $NF}‘ awk.txt
line.
are.
tomas,jason.

NR:行数

示例:如果指定一个文件就显示一个文件的行数,如果指定两个文件就显示两个文件的行数

[root@localhost ~]# awk ‘{print NR}‘ awk.txt
1
2
3
[root@localhost ~]# awk ‘{print NR}‘ awk.txt/etc/issue
1
2
3
4
5
6
7
8
9


 FNR:行数,各文件单独计数

示例:各文件单独计数

[root@localhost ~]# awk ‘{print FNR}‘ awk.txt/etc/issue
1
2
3
1
2
3
4
5
6

  

FILENAME:当前文件的文件名

[root@localhost ~]# awk ‘{print FILENAME}‘ awk.txt/etc/issue
awk.txt
awk.txt
awk.txt
/etc/issue
/etc/issue
/etc/issue
/etc/issue
/etc/issue
/etc/issue

 

ARGC:awk命令行中的参数个数

[root@localhost ~]# awk ‘{print ARGC}‘ awk.txt
2
2
2
[root@localhost ~]# awk ‘{print ARGC}‘ awk.txt/etc/issue
3
3
3
3

 awk和文件名是参数


ARGV:数组,保存了命令行参数本身

示例:显示第一个参数和第二个参数

[root@localhost ~]# awk ‘{print ARGV[0]}‘ awk.txt
awk
awk
awk
[root@localhost ~]# awk ‘{print ARGV[1]}‘ awk.txt
awk.txt
awk.txt
awk.txt

2.2自定义变量

 (1)  -v VAR_NAME=VALUE

     变量名区分字符大小写

 (2)在program中自定义变量

示例:在program中定义变量;定义的变量为f1=3,输出$f1就是输出第三字段

[root@localhost ~]# awk‘BEGIN{FS=":";f1=3}{print $f1}‘ /etc/passwd
0
1
2

 

3、printf命令

语法:printf FORMAT,item1,item2,……

要点:

(1)  必须提供FORMAT

(2)  与print语句不同,printf不会自动换行,需要显式指定换行符:\n

(3)  FORMAT中需要分别为后面的每个item指定一个格式符,否则item则无法显示

格式符:都以%开头,后面跟单个字符

   %c:显示字符ASCII码

   %d,%i:显示为十进制整数

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

   %f:显示浮点数

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

   %s:显示字符串

   %u:显示无符号整数

   %%:显示百分号自身

示例:如输出%s,恰恰$1就是字符串类型所以会输出

[root@localhost ~]# awk -F: ‘{printf "This isuser:%s.\n",$1 }‘ /etc/passwd
This is user:root.
This is user:bin.
This is user:daemon.

两个格式符一起输出

[root@localhost ~]# awk -F: ‘{printf "This isuser:%s,his UID is %d.\n",$1,$3 }‘ /etc/passwd
This is user:root,his UID is 0.
This is user:bin,his UID is 1.
This is user:daemon,his UID is 2.

注意:格式会和对应的段进行匹配,匹配到了就会输出,如果输出的段没有匹配的格式是不会显示的,如下示例,只有两个格式,但是输出三个段,那么最后一个段不会显示

[root@localhost ~]# awk -F: ‘{printf "This isuser:%s,his UID is %d.\n",$1,$3,$7 }‘ /etc/passwd
This is user:root,his UID is 0.
This is user:bin,his UID is 1.

如果想显示第七段必须要给对应的格式符

[root@localhost ~]# awk -F: ‘{printf "This isuser %s, his UID is %d, his shell is %s.\n",$1,$3,$7}‘ /etc/passwd
This is user root, his UID is 0, his shell is/bin/bash.
This is user bin, his UID is 1, his shell is/sbin/nologin.
This is user daemon, his UID is 2, his shell is/sbin/nologin

 

修饰符:

   #[.#]:

      左边的#:用于指定宽度

      右边的#:显示精度

   +:显示数值字符

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

示例:第一个字段占20各字符显示,第三个字段占20各字符左对齐显示

[root@localhost ~]# awk -F: ‘{printf"%20s:%-20d\n",$1,$3}‘ /etc/passwd
               root:0                  
                bin:1                  
             daemon:2

第一个字段和第三个字段分别占20各字符并且左对齐

[root@localhost ~]# awk -F: ‘{printf"%-20s:%-20d\n",$1,$3}‘ /etc/passwd
root               :0                  
bin                :1                  
daemon             :2


4、操作符

算术操作符:

x+y, x-y, x*y, x/y, x^y, x%y

-x: 负值

    +x: 转换为数值

字符操作符:没有操作符,就一个字符串连接

   赋值操作符:

       =, +=, -=, *=,  /=, %=, ^=

       ++,--

   比较操作符:

      >, >=, <. <=, ==, !=

   模式匹配操作符:

       ~:是否能由右侧指定的模式所匹配;         

      !~:是否不能由右侧指定模式所匹配

逻辑操作符:

   &&:与运算

   ||:或运算

   !:非运算

   条件表达式:

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

     挑选器:如果为真运行:如果为假运行

 

   函数调用:

      function_name(argu1,argu2,...)

 

示例:如果用户id大于500,则输出common user如果小于500输出sysuseror admin

[root@localhost ~]# awk -F:‘{$3>=500?usertype="common user":usertype="sysuser oradmin";printf "%-15s:%s\n",$1,usertype}‘ /etc/passwd
rpcuser       :sysuser or admin
nfsnobody     :common user
pulse         :sysuser or admin
sshd          :sysuser or admin
tcpdump       :sysuser or admin
centos        :common user
gentoo         :common user

输出当前系统每个分区的空间使用情况

[root@localhost ~]# df -h | awk ‘{printf"%-25s:%-s\n",$1,$5}‘
Filesystem               :Use%
/dev/mapper/vg0-root     :2%
tmpfs                    :0%
/dev/sda1                :16%
/dev/mapper/vg0-usr      :21%
/dev/mapper/vg0-var      :2%

5、PATTERN

(1)  empty:空模式,匹配所有行

如:awk ‘{print $NF}‘ /etc/passwd就是空模式

(2)  /Regular Expression/:仅将ACTION应用于能被Regular Expression所匹配到的行。

显示ab开头的用户名和uid

[root@localhost ~]# awk -F: ‘/^[ab]/{print $1,$3}‘/etc/passwd
bin 1
adm 3
avahi-autoipd 170
abrt 173
apache 48

(3)  Relational Expression:关系表达式,即结果为的表达式,或者其结果类同于的表达;一般来说,其结果为非0数值或非空字符串即可为“真”,否则,则类同为

显示出uid大于500的用户

[root@localhost ~]# awk -F: ‘$3>=500{print$1,$3}‘ /etc/passwd
nfsnobody 65534
centos 500
gentoo 501

显示用户的shell为bash的用户

[root@localhost ~]# awk -F: ‘/bash$/{print $1,$7}‘/etc/passwd
root /bin/bash
centos /bin/bash
gentoo /bin/bash

显示指定字段的指定内容:如显示用户为root的用户并输出

[root@localhost ~]# awk -F: ‘$1~/root/{print$1,$7}‘ /etc/passwd
root /bin/bash

如果不添加指定字段匹配root会输出

[root@localhost ~]# awk -F: ‘/root/{print $1,$7}‘/etc/passwd
root /bin/bash
operator /sbin/nologin

(4)  line ranges:行范围,类似与sed或vim中的地址方式

startline,endline

 

(5)  BEGIN/END:两个特殊模式

BEGIN:在文件格式化操作开始之前事先执行的一次操作;通常用于输出表头或做出一个预处理操作;

END:在文件格式操作完成之后,命令退出之前执行的一次操作;通常用于输出表尾或做出清理操作;

示例:打印一个表头

[root@localhost ~]# awk -F: ‘BEGIN{printf"%-20s%s\n---------------------------\n","UserName","UserID"}{printf"%-20s:%-d\n",$1,$3}‘ /etc/passwd
UserName           UserID
---------------------------
root               :0
bin                :1
daemon             :2

输出表尾

[root@localhost ~]# awk -F: ‘BEGIN{printf"%-20s%s\n---------------------------\n","UserName","UserID"}{printf"%-20s:%-d\n",$1,$3}END{print "----------------\nend"}‘/etc/passwd
centos             :500
gentoo             :501
zabbix             :496
----------------
end

BEGIN对变量赋值

[root@localhost ~]# awk‘BEGIN{FS=":"}{print $1,$3}‘ /etc/passwd
root 0
bin 1
daemon 2

6、常用的ACTION

(1) Expressions:例如变量赋值

(2) Control statements:控制语句,如if,while等

(3) Compound statements:复合语句

(4) input statements

(5) output statements


7、控制语句

7.1 if-else

语法:

   if (condition)statement [ else statement ]

   if (condition){statements} [else {statements}]

示例:输出uid大于500的用户,单分支if实现

[root@localhost ~]# awk -F: ‘{if ($3>=500) print$1,$3}‘ /etc/passwd
nfsnobody 65534
centos 500
gentoo 501

判断用户uid和gid是否相同,如果相同则输出用户名及uid和gid

[root@localhost ~]# awk -F: ‘{if ($3==$4) print$1,$3,$4}‘ /etc/passwd
root 0 0
bin 1 1
daemon 2 2

判断rc.sysinit文件中,字段数大于6的行,并输出行的字段数和行的内容

[root@localhost ~]# awk ‘{if (NF>=6) printNF,$0}‘ /etc/rc.d/rc.sysinit
8 # /etc/rc.d/rc.sysinit - run once at boot time
9 # Taken in part from Miquel van Smoorenburg‘sbcheckrc.
6 if [ -f /etc/sysconfig/network ]; then

示例:判断用户uid是否大于500,如果大于500输出用户名跟is a common user,否则输出用户名根is a sysadmin or sysuser

[root@localhost ~]# awk -F: ‘{if ($3>=500){print$1,"is a common user"} else {print $1,"is a sysadmin orsysuser"}}‘ /etc/passwd
nfsnobody is a common user
pulse is a sysadmin or sysuser
sshd is a sysadmin or sysuser
tcpdump is a sysadmin or sysuser
centos is a common user
gentoo is a common user

7.2 while循环

语法:while (condition) statement

           while(condition) {statements}

条件为“真”时循环,为“假”时退出循环;

使用场景:通常用于在当前行的各字段间进行循环;

示例:输出issue文件中字符个数大于6的字段

[root@localhost ~]# awk ‘{i=1;while(i<=NF){if(length($i)>=6){print $i};i++}}‘ /etc/issue
CentOS
release
(Final)
Kernel
Education
Learning
Services

说明:length是awk的内置函数,是用来取字段长度的

   7.3do-while循环

语法:do statement while (condition)

          do {statements} while (condtion)

          意义:至少执行一次循环体

   7.4for循环

       语法:for (expr1;expr2;expr3) statement

           for(expr1;expr2;expr3) {statements}

for (variable assignment;codition;iteration process) {for-body}

示例:显示issue文件中字符数大于等于6个的字段

[root@localhost ~]# awk‘{for(i=1;i<=NF;i++){if(length($i)>=6)print$i}}‘ /etc/issue
CentOS
release
(Final)
Kernel
Education
Learning
Services

 

第二种用法:用于遍历数组中的元素

    for(var_name in array) {for-body}

 

比如:weekdays是一个数组

    weekdays

       weekdays[mon]="Monday"

       weekdays[tue]="Tuesday"

       ...

 

    for(i in weekdays):此时,i变量会遍历weekdays数组的每个索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;

       要获取元素的值:weekdays[i]

 

   7.5swtich语句

语法:switch (expression) {case VALUE or /REGEXP/: statement; ...;default: statementN}

类似与shell中的case

   7.6break and continue

       break [n]:退出当前循环,n是一个数字,用于指定退出几层循环

       continue:提前结束本轮循环而进入下一轮

 

   7.7next

      提前结束对本行文件的处理,而提前进入下一行的处理操作;

示例:显示用户id为奇数行的用户名和id

[root@localhost ~]# awk -F: ‘{if($3%2==0)next;print $1,$3}‘ /etc/passwd
bin 1
adm 3
sync 5


8、数组

关联数组:

index-expression:

    可以使用任意字符;

    如果某数组元素事先不存在,则在引用时,awk会自动创建此元素并将其值初始化为空串;

       因此,若要判断数组中的某元素是否存在,要使用“index in array”的方式进行判断;

    要遍历数组中的元素,则要使用for (var_name in array)的方式进行;此时,var_name会遍历array的每个索引,所以,要显示数组元素的值,要使用array[var_name]

weekdays

  weekdays[mon]="Monday"

        weekdays[tue]="Tuesday"

        ...

 

for (i in weekdays):此时,i变量会遍历weekdays数组的每个索引,即mon, tue,而非元素的值“Monday”或"Tuesday"等;

        要获取元素的值:weekdays[i]

注意:awk的数组下标从1开始编号

 

示例:统计count.txt文件中所有行,每个单词出现的次数

[root@localhost ~]# cat count.txt
How are you? How old are you?
What are you doing?
[root@localhost ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++}}END{for(j in count) {print j,count[j]}}‘ /root/count.txt
are 3
What 1
How 2
doing? 1
old 1
you? 2
you 1

for(i=1;i<=NF;i++):遍历所有字段

{count[$i]++}:将字段遍历结果赋值给数组,$i是数组的下标,遍历一边$i就加1

END{ }:循环数组显示统计结果

for(j in count):使用变量j遍历count数组的每一个下标

print j:输出单词名字

count[j]:输出单词出现的数量,由于每次遍历count数组出现相同的单词j就会加1,直到最后匹配不到位置,j最后的值就是单词出现的次数

 

单独统计每一行单词出现个数

[root@localhost ~]# awk ‘{for(i=1;i<=NF;i++){count[$i]++};for(j in count) {print j,count[j]};delete count}‘ /root/count.txt
are 2
How 2
old 1
you? 2
are 1
What 1
doing? 1
you 1

delete count:每一行统计完成之后置空,数组

 

统计tcp连接状态

[root@localhost ~]# ss -tan | awk‘!/^State/{state[$1]++}END{for(i in state)print i,state[i]}‘
ESTAB 1
LISTEN 12

!/^State:去除第一行显示

{state[$1]++}:设置数组

for(i in state)print i,state[i]:循环数组,打印数组

 

统计web日志文件ip资源访问次数

[root@localhost ~]# awk ‘{ip[$1]++}END{for(i in ip)print i,ip[i]}‘ /var/log/httpd/access_log
172.16.4.230 24
172.16.4.136 4

{ip[$1]++}:循环ip段

for(i in ip):将ip段的值(ip地址)赋值给变量i

print i,ip[i]}:打印ip地址和输出ip的长度

 

9、函数

9.1内建函数

   数值处理:

rand():返回0至1之间的一个随机数;

[root@localhost ~]# awk ‘BEGIN{print rand()}‘
0.237788

   字符串处理:

length([s]):返回指定的字符串的长度;

[root@localhost ~]# awk ‘BEGIN{printlength("hello world")}‘
11

 

sub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其第一次被匹配到的内容替换为s所表示的字符串;

[root@localhost ~]# cat count.txt
How are you? How old are you?
What are you doing?
[root@localhost ~]# awk‘{sub("are","ARE,$0");print $0}‘ count.txt
How ARE,$0 you? How old are you?
What ARE,$0 you doing?

gsub(r,s[,t]):基于r所表示的模式来匹配字符串t中的内容,将其所有被匹配到的内容均替换为s所表示的字符串;

split(s,a[,r]):以r为分隔符去切割字符串s,并将切割后的结果保存至a表示的数组中;

取用户名:将定为分隔符,对整个行进行切割,将结果赋值给userinfo,最后输出userinfo的第一个值

[root@localhost ~]# awk‘{split($0,userinfo,":");print userinfo[1]}‘ /etc/passwd
root
bin
daemon

substr(s,i[,n]):从s所表示的字符串中取子串,取法:从i表示的位置开始,取n个字符;


    时间类的函数:

       systime():取时间戳;

   

    位运算函数:

       and(v1,va2):

      

9.2 自定义函数

    functionf_name(p,q)

    {

       ...

    }


本文出自 “梅花香自苦寒来” 博客,请务必保留此出处http://ximenfeibing.blog.51cto.com/8809812/1654768

awk(未完)

标签:awk

原文地址:http://ximenfeibing.blog.51cto.com/8809812/1654768

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!