当前位置: 首页 > linux教程 >

shell脚本之awk用法练习

1. grep 更适合单纯的查找或文本匹配

2.sed 更适合编辑匹配到的文本

3. awk 更适合格式化文本,对文本进行较复杂格式处理

4. awk 最常用的动作  print printf

$0 表示整行 NF 表示该列被分割成几列字段,倒数第二列 $(NF-1) $NF 表示当前分割后最后一列  

5. awk 2中特殊处理模式 :  BEGIN  END

    BEGIN : 指定可处理文本前需要执行的操作

    END     : 指定处理完所有行需要执行的动作

6.    内置变量

    输入分隔符 field separator  FS

    输出分隔符 output field separator OFS

    awk -F# '{print $1 $2}' test

    awk -v FS='#' '{print $1 $2}' test

    awk -v OFS="+++" '{print $1,$2}' test  

    输入换行符  RS

    输出换行符   ORS

    当前行字段个数  NF

    当前处理文本行号  NR  多文件时,会按文件顺序 行号递增

    各个文件分别计数行号  FNR  多文件时,会按各自文件 行号显示

    档期文件名  FILENAME

    命令行参数格式  ARGC

    参数数组 ARGV

    awk 'BEGIN{print argv[0],argv[1],argv[2])' test1 test2 //  nawk 未实现,不知道原因

    自定义变量 awk 'BEGIN{aa="111";print "123",aa}' tt.txt

    awk -v TT="123" 'BEGIN{print "123",TT}' tt.txt     //  也未实现 ,不知道原因

    awk -v FS="#" '{printf "第一列: %s\t   第二列:  %s \n",$1,$2}'  test

    awk  负责文本切割 printf  负责格式化输出

     awk '/^123/{print $0}' 1.txt

     awk '{if (NR > 1 && NR <4 ){print $0}}' 1.txt

     awk '{if(NR == 1 ){print $2,$3} else if(NR ==2){print $1}else {print $0}}' 1.txt

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


语法格式:awk [选项]  '指令'  操作文件

常用选项:-F  指定分隔符,分隔符用""引起来

-v:var=value在awk程序开始之前指定一个值valu给变量var,这些变量值用于awk程序的BEGIN快

-f:后面跟一个保存了awk程序的文件,代替在命令行指定awk程序

实例1:在命令行直接输入awk指令

awk  '{print}'  1.txt   #逐行读取文件1.txt内容并打印

awk '{print $0}' 1.txt  #逐行读取文件内容,并打印该行,$0保存的是当前行的内容

awk '{print "hello"}'  1.txt   #逐行读取1.txt文件内容,每行结束后打印一个hello,文件1.txt有多少行就打印多少个hello

awk  '{print $1}'   1.txt   #打印1.txt的第一列内容,在不指定分割符的情况下,awk默认使用空白做分割符

awk   -F ":"  '{print $1}'  /etc/passwd     #以":"为分隔符打印/etc/passwd文件的第一例内容

实例2:将awk指令写入文件,通过-f选项调用

vim  awkscript

BEGIN {

FS=":"

}

{print $1}

awk -f awkscript  /etc/passwd  #通过调用awk指令文件来执行awk命令

实例3:awk的BEGIN块和END块

BEGIN用于初始化FS变量(列分隔符),打印标题,或者初始化后需要在程序中调用的全局变量

END用于执行最后的运算或者打印最终的输出结果

END块和BEGIN不是必须的

实例4:在awk中使用正则匹配,正则表达式必须要放在//中

awk '/123/{print}'   1.txt   #打印1.txt中匹配123的那一行内容

awk -F ":"   '/123/{print  $2}'  1.txt   #以":"为分隔符打印1.txt中匹配123的那一行中,第二列的内容

awk -F ":"  '$1 ~ /root/{print $2}'   /etc/passwd  #打印/etc/passwd中,第一列匹配root的行其第二列的内容 ~表示匹配

实例5:awk的表达式和块

awk提供了多个比较操作符:"=="  ">" "<"  "<=" ">="  "!="   "~"匹配    "!~"不匹配

awk 'BEGIN{ FS=":"}  $1 == "root"  {print $3}'   /etc/passwd  #以":"为分隔符,打印/etc/passwd中第一列是root的行其第3列的内容

实例6:awk中的条件语句

awk 'BEGIN {FS=":"} {if ($1 ~ "root") {print $2}}'   /etc/passwd # 以":"为分隔符,打印/etc/passwd文件中第一列匹配root的行,其第二列的内容

awk  'BEGIN {FS=":"}  ($1 ~ "linux" || $2 ~ "Network")  {print $3}'   1.txt  # 以":"为分隔符,打印1.txt文件中,第一列匹配linux或者第二列匹配Network的行,其第三列的内容

在awk中NF变量记录的是当前行中有多少列(默认是空格为分割符)

NF变量,也叫做“字段数量”变量。awk会自动将该变量设置成当前记录中的字段数量。可以使用NF变量来只显示某些输入行:


  1. NF == 3 { print $1,$2,$3 } 

NR变量始终包含当前记录的编号(awk将第一个记录算作记录号1)。迄今为止,我们处理的输入文件每一行包含一个记录,对于这些情况,NR就是当前行号。可以象使用NF变量一样使用NR来只打印某些输入行:


  1. (NR < 10 ) || (NR > 100) { print "We are on record number 1-9 or 101+" } 
  2.  

awk '/ock/{print NF}' 1.txt  # 统计匹配ock的行有多少列

awk 'NF == 3 {print}'   1.txt   #打印1.txt中有3列的行的内容,示例中,第二行有三列,所以打印的就是第二行的内容

$NF记录的是当前行最后一列的内容(如果每一行有多列内容)

awk '{if (NR > 3) {print $NF} }' 1.txt       # 输出1.txt中行号大于3的行,其最后一列的内容 

NR记录的是当前行的行号

awk  '{if  (NR > 3)  {print NR". "$0} }'  1.txt   #格式化输入1.txt中行号大于3的行的行号和内容

awk  'BEGIN { x=0 }  /^$/{x=x+1} END{print "find" " " x " " "blank  lines"}'    1.txt   #统计1.txt中有多少空行

awk  '{print ($2**2) +1}'   3.txt   #将3.txt文件中第二列内容做平方运算后再加1输入(字符串做平方运算后结果为0)

awk脚本示例1:

功能:打印1.txt文本中每一列的内容

#!/bin/bash
num=`wc 1.txt | awk '{print $2}'`     # 统计1.txt文件有多少列
for i in `seq 1 $num`                       # 根据文件列数进行循环
do
  awk -v a=$i  '{print $a}' 1.txt         # 打印每一列的内容,-v 参数可以指定一个变量保存外部变量的值,将外部变量传递给awk
done

示例2:

使用awk查看当前系统中的TCP连接状态和对应状态的连接数

netstat -n | awk '/^tcp/ {++T[$NF]} END {for(key in T) print key,T[key]}'

#使用netstat  -n 查看网络连接,/^tcp/匹配以tcp开头的连接,将其匹配行的最后一列内容(即TCP的连接状态)作为下标生成数组T[],++T[$NF]表示每匹配一次,将该下标的元素值加1,左后在END 中遍历数组,输出对应TCP连接状态的值

]

 

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

awk是一个优良的文本处理工具,print是打印命令 $0 是代表当前行  $1代表第一个字段 …
 
1. -F 制定分割符为…(例如:为  ' :')
 
打印以 :号分割  第一二个字段
 
awk   -F  ':' '{print $1 $2}' /etc/passwd
 
 
awk的常用变量
 
一. NF :表示最后一个字段     
 
1 .打印etc/passwd下的最后一个字段
 
awk -F ':' '{print $NF}' /etc/passwd
 
 
2.$(NF-1)表示倒数第二个字段    打印倒数第二个字段
 
awk -F ':' '{print $(NF-1)}' /etc/passwd
 
 
二  .  NR 当前处理的是第几行
 
 1.输出第二行
 
awk -F ':' 'NF==2 {print}' /etc/passwd
 
 
2.输出第三行以后的行
 
awk -F ':' 'NF>3 {print}' /etc/passwd
 
 
三 .  awk 内置函数
 
1. toupper  用于将字符转为大写  将小写转化为大写并且打印第一个字符
 
awk -F ':' '{print toupper($1)}' /etc/passwd
 
 
 2. 将 小写转化为大写
 
awk -F ':' '{print tolower($1)}' /etc/passwd
 
 
 四.awk允许指定输出条件 ,只输出符合条件的行
 
 1.打印包含root的行
 
awk -F ':' '/root/ {print}' /etc/passwd
 
 2.输出第一个字段等于指定值的行     (第一个字段是root的打印出来)
 
awk -F ':' '{if($1=="root") print $1;else print $2}' /etc/passwd
 
 3. 假如$1== root 打印第一个字段  否则打印第二个字段
 
 
 
 五.高级用法 BEGIN END
 
 1.计算1-100的和
 
seq 100 | awk '{sum+=$0} END {print sum}'
 
 2.销售金额
 
cat sale
一:60件:300
一:80件:450
一:100件:500

awk -F ':' 'BEGIN {print $3;total=0} {$3;total=total+$3;} END {printf "销售总金额:%.2f ",total}' sale
 
销售总金额:1250.00

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


 2.3 表达式和运算符
awk 允许使用正则表达式,根据正则表达式是否匹配当前行来选择执行独立代码块。以下示例脚本只输出bill中包含字符序列8613902700003的那些行:

		
  1. awk '/8613902700003/ { print }' bill 
 当然,可以使用更复杂的正则表达式:

		
  1. /[0-9]*/ { print } 
下面列出正则表达式元字符:
字符 描述
. 可代替除一行之外的任何单个字符
* 可代替零个或多个在它前面出现的字符
[chars] 可代替chars中的任何一个字符,chars是一串字符序列。你可以用-符号来定义一个字符范围。如果^是chars中的第一个字符,那么将匹配没有在chars中指定的字符
^ 匹配一行的开头
$ 匹配一行的结尾
  把后面的字符照常输出,通常用来转义(不使用特殊含义)一个元字符
 
 
除了使用正则表达式来选择行,我们也可以使用布尔表达式来选择行。使用方法是将布尔表达式放在代码块之前,仅当对前面的布尔表达式求值为真时,awk才执行代码块。以下示例脚本将输出bill中第四个字段等于8613902700003的所有行中的第三、四字段。如果当前行的第四个字段不等于8613902700003,awk将继续处理文件而不对当前行执行print语句:
 

		
  1. $4 == "8613902700003" { print "OrgAddr: "$3, " DestAddr: "$4 } 
 
注意,代码块前的布尔表达式必须与代码块在同一行上。
awk 提供了完整的比较运算符集合,包括"=="、"<"、">"、"<="、">="和"!="。另外,awk还提供了"~"和"!~" 运算符,它们分别表示“匹配”和“不匹配”。它们的用法是在运算符左边指定变量,在右边指定正则表达式。例如:
 

		
  1. $4 ~ /8613902700003/ { print "OrgAddr: "$3, " DestAddr: "$4 } 
 
awk还允许使用布尔运算符"||"(逻辑或)和"&&"(逻辑与),以便创建更复杂的布尔表达式:

		
  1. ( $3 == "8613902700001" ) && ( $4 == "8613902700003" ) { print } 
 
awk的另一个优点是它有完整的数学运算符集合。除了标准的加、减、乘、除,awk还允许使用指数运算符"^"、模运算符"%"和其它许多从C语言中借入的易于使用的赋值操作符。
这些运算符包括前后加减(i++、--j)、加/减/乘/除赋值运算符(a+=3、b*=2、c/=2.2、d-=6.2)。不仅如此,还有易于使用的模/指数赋值运算符(a^=2、b%=4)。
 
2.4 字符串化变量
awk变量“字符串化”是指所有awk变量在内部都是按字符串形式存储的。而且只要变量包含有效数字字符串,就可以对它执行数学操作,awk会自动处理字符串到数字的转换步骤。请看以下这个示例:

		
  1. BEGIN   { x="0" } 
  2. /^$/    { x=x+1 } 
  3. END     { print "I found " x " blank lines. :)" } 
这个例子的功能是计算文件中空白行的数量,^$表示空行。如果做一个小实验,就可以发现如果某个特定变量不包含有效数字,awk在对数学表达式求值时会将该变量当作数字0处理。
3 第二部分:提高
3.1 处理多行
 
在这一节里,顺带着讲一下三个特别的变量:
Awk特殊变量 描述
RS 表示记录分隔符
OFS 表示输出字段分隔符,在两个单独的字段间插入定义的字符串
ORS 表示输出记录分隔符,在两个单独的记录间插入定义的字符串
第一部分我们讨论的都是一个记录占用一行的情况,如果要分析占据多行的记录,除了依靠FS,还需要设置RS(记录分隔符变量)。RS变量告诉awk当前记录什么时候结束,新记录什么时候开始。
为了便于讨论,我们依然首先在当前目录下生成一个通讯录文件address,其内容如下:

zhangsan 13712345678 zhs@hotmail.com lisi 13012345678 ls@21cn.com

要处理这个文件,可以将每三行看作是一个独立的记录,一个记录包含三个字段。如下脚本将原记录由三行转换成一行输出:
 

		
  1. BEGIN { 
  2.     FS=" " 
  3.     RS="" 
  4.   
  5.     print $1 ", " $2 ", " $3 
 此代码将产生以下输出:

zhangsan, 13712345678, zhs@hotmail.com lisi, 13012345678, ls@21cn.com

在上面例子中,为了在三个字段之间插入一个逗号和空格,使用了", "。这个方法虽然有用,但比较难看。其实我们还有更好的方法,那就是设置变量OFS(输出字段分隔符)。OFS缺省情况下被设置成" "(单个空格)。使用如下脚本可以达到上面例子同样的效果:

		
  1. BEGIN { 
  2.     FS=" " 
  3.     RS="" 
  4.     OFS=", " 
  5.   
  6.     print $1, $2, $3 
awk还有一个特殊变量ORS(输出记录分隔符)。ORS缺省情况下被设置成" ",如果我们将其设为" ",就可以使输出记录的间隔翻倍。例子就不举了,大家可以自己试试。个空格分隔记录(而不换行),将ORS设置成" "。
需要注意的是,使用上面的方法,最多只能处理一个记录占用三行的文本,象下面一个记录占据四行的通讯录,就处理不了了(大家可以试试看):

wangwu 13512345678 ww@163.com wuhan, hubei

 要处理这种情况,代码最好考虑每个记录的字段数量,并依次打印每个记录。以下就是修正的代码:

		
  1. BEGIN { 
  2.     FS=" " 
  3.     RS="" 
  4.     ORS="" 
  5.   
  6. {  
  7.         x=1 
  8.         while ( x<NF ) { 
  9.                 print $x " " 
  10.                 x++ 
  11.         } 
  12.         print $NF " " 
程序输出如下:

 wangwu 13512345678 ww@163.com wuhan, hubei


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


awk中print与printf的主要差别显示在以下两点:

  1. print在显示多个结果的时候以逗号分隔,结果将这几部分的内容自动使用分隔符进行分隔,且不需要添加换行符
  2. printf可以更加灵活的控制某一个字段的输出格式,通过使用诸如%-12s,%3.1f等格式化方法
 
------分隔线----------------------------
  • 收藏
  • 挑错
  • 推荐
  • 打印