全部博文(180)
分类: 系统运维
2010-02-14 17:37:42
Awk/Gawk 编程命令整理
(本博文旨在归纳awk/gawk的命令,前面的多篇博文中演示了 gawk 的使用,
例如:
http://blog.chinaunix.net/u3/105477/showart_2088280.html
http://blog.chinaunix.net/u3/105477/showart_2088383.html
http://blog.chinaunix.net/u3/105477/showart_2088392.html
http://blog.chinaunix.net/u3/105477/showart_2088393.html )
1. 关于 awk 和 gawk 语言
gawk是所开发的awk。
awk 是一种程序语言,对于资料的处理具有很强的功能,可以使用很短的代码轻易地完成对文本档案做修改、分析、提取和比较等处理。 如果用C或Pascal等语言编写程序完成上述功能,需要花费较多的时间编写很长的代码。
一、调用AWK
一共有三种方法分别如下:
1.1 awk [-F field-separator] ‘commands’ input-file(s)
这里面的commands 是真正的AWK命令。其中 [-F域分隔符] 是可选的指定域分隔符
示例:awk –F ‘commands’ input-file
1.2 将所有awk命令插入一文件,并使awk程序可执行。
相当于编写一个可执行SHELL脚本
1.3 将所有的AWK命令插入一个单独文件,然后调用
PS:其中的-F设置好一个文本行的域分隔符号
二、示例
有一个文本内容如下:
M.Tan 05/99 48311 Green 8 40 44
J.Lun 06/99 48317 green 9 24 26
P.Bun 02/99 48 Yello 12 35 28
共有七个域。域与域之间是通过空格进行分隔开的。故不必用-F 选项处理
2.1 保存AWK输出
awk '{print $0}' grade.txt > out 覆盖同名文件
awk '{print $0}' grade.txt > >out 追加同名文件
2.2 保存的同时再打印输出
awk '{print $0}' grade.txt | tee out 表示在写入文件的同时也会一并打印输出来
2.3 使用标准输入
AWK脚本都是从标准输入中接受输入。
$ belts.awk < grade.txt 表示从此文件中输入进来处理
也可用管道 $grade.txt | belts.awk 表示将此文件丢到后面的AWK脚本处理
2.4 打印所有记录
awk '{print $0}' grade.txt
PS:$0 将打印一整行出来
当用AWK遇到错误的时候如何排查:
1、 确保整个awk命令用单引号括起来
2、 确保命令内所有引号成对出现。
3、 确保用花括号括起来动作语句,用圆括号括起来条件语句
PS:条件语句是用if() {} 组成一个集合进来
我们这里面的正则表达式均使用斜线括起来。示例/Green/这样的形式
在调用AWK命令之前可以使用正则表达式做一些过滤
元字符如下:
\ ^ $ . [] | () * + ?
其中的 + 与 ? 只适用于awk不适用于sed与grep
示例:
awk '{print $4}' grade.txt
输出:
Green
green
Yello 字段从1开始的1 2 3 4 5 以-F指定的进行分割处理
PS:哦 AWK是指定字段之间的分隔符了如果没有指定就是空白符了如果指定了就用指定的进行分割处理。然后分割完了之后就会得到一系列的域出来分别用$1 开始表示如果用$0则表示全部的内容都打印出来!
示例:awk '{if($4!~/green/) print $0}' grade.txt
输出:
M.Tan 05/99 48311 Green 8 40 44
P.Bun 02/99 48 Yello 12 35 28
PS:
4、 确保整个awk命令用单引号括起来
5、 确保命令内所有引号成对出现。
6、 确保用花括号括起来动作语句,用圆括号括起来条件语句
(条件表达式是用() 括起来的)
示例:awk '{if ($6<$7) print $0 "$1 try better at the next comp "}' grade.txt
输出:
M.Tan 05/99 48311 Green 8 40 44$1 try better at the next comp
J.Lun 06/99 48317 green 9 24 26$1 try better at the next comp
输入:awk '{if ($6<=$7) print $0 "$1 try better at the next comp "}' grade.txt
输出:
M.Tan 05/99 48311 Green 8 40 44$1 try better at the next comp
J.Lun 06/99 48317 green 9 24 26$1 try better at the next comp
输入:awk '{if ($6>$7) print $0 "$1 try better at the next comp "}' grade.txt
输出:P.Bun 02/99 48 Yello 12 35 28$1 try better at the next comp
可用[] 符号。示例awk '/[Gg]reen/' grade.txt
输出:
M.Tan 05/99 48311 Green 8 40 44
J.Lun 06/99 48317 green 9 24 26
可以用| 表示或关系运算。类似于or运算符
不过一定要用() 括起来
输入:awk '$0~/(Yello|brown)/' grade.txt
输出:P.Bun 02/99 48 Yello 12 35 28
PS:|表示或运算符这个表示或者或者注意一下区别
复合模式:
&& AND: 表示只有两边同时为真的时候才成立
|| OR: 表示只要有一个为真
! 非
输入:awk '{if ($1=="P.Bun" && $4 == "Yello") print $0}' grade.txt
输出:P.Bun 02/99 48 Yello 12 35 28
PS:AWK编程与程序是一样的哦!
表示程序中为or运算符。
输入:awk '{if ($1=="P.Bun" || $4 == "Yello") print $0}' grade.txt
输出:P.Bun 02/99 48 Yello 12 35 28
PS:以上列举了常用的运算符。可以应用于逻辑编程
9.2.6 AWK内置变量
PS:相当于程序中的内置变量值
表:
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME AWK浏览的文件名
FNR 浏览文件的记录数
FS 设置输入域分隔符。等价于命令-F选项
NF 浏览记录的域个数
NR 读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
示例:
输入:awk 'END {print NR}' grade.txt
输出:3
PS:打印查看记录个数
9.2.7 操作符
常用的操作符如下列表
= += *= / = %= ^ = 赋值操作符
? 条件表达操作符
| && ! 并、与、非
~ !~ 匹配操作符,匹配与不匹配(匹配即模糊概念)
< <= = = != >> 关系
+ - * / % ^ 算术
++ -- 前缀和后缀
示例:
awk '{name=$1;belts=$4;if(belts ~/Yello/) print name "is test"}' grade.txt
解释:可以将域变量赋给一个新变量,然后在后面引用进来!
输出:P.Bunis test
awk '{if($6<27) print $0}' grade.txt
解释:表示第几个字段的值提取出来进行比较条件符合就输出
输出:J.Lun 06/99 48317 green 9 24 26
awk 'BEGIN {BASELINE="27 " }{if($6 < BASELINE) print $0}' grade.txt
解释:可以在前面定义好变量然后在后面直接引用进来就行!
输出:J.Lun 06/99 48317 green 9 24 26
发现在一个AWK表达式中可以使用多个{}将AWK表达式定义进来
修改数值域取值
命令:awk '{if($1=="M.Tan") $6=$6-10;print $1,$6,$7}' grade.txt
输出:
M.Tan 30 44
J.Lun 24 26
P.Bun 35 28 (可以将第6个值域少10)(符合条件的就修改过来)
PS:语句之间的分隔请用; 分号 。字符表示请用”” 双引号表示
但是这种修改并没有对原来的文件修改过。只是其缓冲区的内容变更过来!
IF语句中如果有超过多条记录的时候请记得用{} 括起来(非常类似于其他的编程语言)
示例:awk '{if($1=="M.Tan") {$1="M.J.Mod";print $1}}' grade.txt
输出:
M.J.Mod (这就是将IF成立的语句全部放在{}中)
PS:AWK语句中的IF语句与实际其他编程语言是相通的即将IF语句后面的内容放入到IF后面的{}中去!IF语句后面的多个语句之间请用; 进行分割处理
创建新的输出域
输入:
awk 'BEGIN{print "Name\t Difference"} {if($6<$7){$8=$7-$6;print $1,$8}}' grade.txt
输出:
Name Difference
M.Tan 4
J.Lun 2
PS:在一条AWK语句中可以写多个{}分割开来处理的!而且可以创建新的字段域进来
还可以对新域创建新的名字出来
如下:
awk 'BEGIN{print "Name\t Difference"} {if($6<$7){diff=$7-$6;print $1,diff}}' grade.txt
对新建的域可以取个好的名字
累记统计某一列累加之和
输入:awk '(toa+=$6); END{print "total is :" toa}' grade.txt
输出:
M.Tan 05/99 48311 Green 8 40 44
J.Lun 06/99 48317 green 9 24 26
P.Bun 02/99 48 Yello 12 35 28
total is :99 (统计第六列的字段取其和)
PS:上面我们定义过了BEGIN关键字这又定义了END关键字。表示在打印输出之后的开始行是输入什么与结束行输入什么!
以上打印是将其记录全部都打印出来了。如果记录过多不是想要的结果那可以这样写:
awk '{(toa+=$6)}; END{print "total is :" toa}' grade.txt
PS:可以在AWK语句中使用正则表达式模式匹配
示例:ls -l |awk '/^-/ {print $9}'
表示前面的输出会经过一个正则匹配处理之后再打印出来的!
(即前面的正则表达式的作用就是为了匹配输出符合条件的内容出来)
OK!到此为止表达式什么的都学习完了。发现其语法跟其他的MS一样的。现在来看下其内置的函数。通过这些函数能够快速解决问题!
内置的字符串函数
AWK内置字符串函数列表
Gsub(r,s) 在整个$0中用s替代r
Gsub(r,s,t) 在整个t中用s替代r
Index(s,t) 返回s中字符串t的第一位置
Length(s) 返回s的长度
Match(s,r) 测试s是否包含匹配r的字符串
Split(s,a,fs) 在fs上将s分成序列a
Sprint(fmt,exp) 返回经fmt格式化后的exp
Sub(r,s) 用$0中最左边最长的子串代替s
Substr(s,p) 返回字符串s中从p开始的后缀部分
Substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分
PS:总体来讲与其他语言的字符串符数功能差不多的。现在详细整理下其使用方法
1、 gsub
表示替换一个字符串为另一个,使用正则表达式,/目标模式/,替换模式/
模式与替换掉的文本之间是用, 号进行分割的
示例:
输入:awk 'gsub(/48/,4880) {print $0}' grade.txt 即在AWK表达式中使用正则模式
输出:
M.Tan 05/99 4880311 Green 8 40 44
J.Lun 06/99 4880317 green 9 24 26
P.Bun 02/99 4880 Yello 12 35 28 (替换掉)
2、 index 查询字符串s中t出现的第一位置。必须要用双引号将字符串括起来。
输入:awk 'BEGIN {print index("Green","e")}' grade.txt
(得到其索引下标值)
输出:3
3、 返回所需字符串长度。
输入:awk '{if($1=="M.Tan") {print length($1) " " $1}}' grade.txt
输出:
调用此字符串函数进来!
还有一种办法awk 'BEGIN {print length("this is a hello")}' 直接对一个字符串进行取函数
输出:15
4、 match
测试目标字符串是否包含查找字符的一部分。可以对查找部分使用正则表达式,返回值为成功出现的字符排列数。如果未找到返回0.
示例:awk 'BEGIN {print match("ANCS",/d/)}'
输出:0 表示目标字符串ANCS中不存在要找的字符值
输入:awk 'BEGIN {print match("ANCS",/S/)}'
输出:4 表示找到了要查找的字符位置为 4
5、 split
使用这个函数返回字符串数组元素个数。
工作方式如下:
如果一字符串包含指定分隔符可以将其划分为一个数组,便可用split指定分隔符及数组名
示例split(“AD2-125-56”,myarray,”-”)
这样myarray[1] = “AD2” 返回了一个数组出来了!
6、 sub
使用这个函数发现并替换模式的第一次出现的位置
示例:
?
7、 substr
它按照起始位置及长度返回字符串的一部分。
输入:awk '$1 == "J.Lun" {print substr($1,1,2)}' grade.txt
输出:J. (相当于将一个字符串进行了分割输出)
AWK中使用的屏蔽序列(即表示转义过的字符)
\b 退格键 \t tab键
\f 走纸换页 \ddd 八进制值
\n 新行 \c 任意其他特殊字符
\r 回车键
介绍一下awk输出函数printf使用
处理格式化输出功能。如按列输出、左对齐、右对齐
语法:printf([格式控制字符],参数)
修饰符如下:
. 左对齐
Width 域的步长,用0表示0步长
.prec 最大字符串长度,或小数点右边的位数
AWK中的printf格式
%c ASCII字符
%d 整数
%e 浮点数
%f 浮点数
%g awk决定使用哪种浮点数转换e或f
%o 八进制
%s 字符串
%x 十六进制
常用的操作:
1、 字符转换
echo "65" | awk '{printf "%c\n",$0}' 使用了%c 的格式化参数
输出:A
awk 'BEGIN {printf "%f\n",999}'
输出:999.000000
PS:其格式化输出的格式为:printf([格式控制字符],参数) printf(“%f\n”,999)
2、 格式化输出
输入:awk '{printf "%-15s %s\n",$1,$3}' grade.txt
输出:
M.Tan 48311
J.Lun 48317
P.Bun 48
PS:按照指定的格式进行输出来。表示格式化输出!
编写awk脚本文件
可以将awk脚本写入到一个文件再去执行。可以创建一个awk扩展名的文件出来
awk数组
输入:awk 'BEGIN{print split("123#456#789",myarray,"#")}'
打印:3
得到一个数组出来数组的内容:
Myarray[1] = “
遍历的方法:
For (ele in array) print array[ele]
输入:awk 'BEGIN{record="123#456#789"; split(record,myarray,"#")} END{for(i in myarray) {print myarray[i]}}' /dev/null
PS:注意要用 /dev/null 作为输入参数哦!要不然就不会输出
输出:
123
456
789
遍历数组的方法!
其它补充:
在awk编程中, BEGIN模式后面跟一个操作模块,如:BEGIN{...},在awk处理输入文件里的任意行之 前执行该模块,其实不用任何输入文件就能测试一个BEGIN操作模块,因为直到BEGIN操作模块完成之后,awk才开始读取输入.BEGIN操作通常用 来改变OFS,FS,RS等awk内制变量的值.
如:
awk 'BEGIN{FS=":";OFS="\t";ORS="\n"}{print $0}' filename
在处理输入文件之前,把域分隔符FS设定成冒号,输出域分隔符OFS设定成TAB键,并把输出记录分隔符ORS设定成一个换行符.
END模式不于任何输入行匹配,但是执行任何与END模式相关的操作.在所有输入行处理完成之后在处理END模式.
如:
awk 'END{print "some strings" NR }' filename
在awk处理完成文件后再执行END模块,NR的值是度入的最后一条记录号.