您的位置:首页 > 运维架构 > Shell

shell编程笔记-文本处理awk

2014-02-18 13:29 603 查看

第八章 文本处理利器 AWK

AWK是一种优良的文本处理工具。它不仅是Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言,三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。

最简单地说, AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当然还从 C 语言中获取了一些优秀的思想。在最初创造 AWK 时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。

尽管操作可能会很复杂,但命令的语法始终是:

awk '{pattern + action}' 或者 awk'pattern {action}'

其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。花括号 ({}) 不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。

gawk 是 AWK 的 GNU 版本。

一般的UNIX作业系统,本身即附有AWK,不同的UNIX作业系统所附的AWK其版本亦不尽相同,若读者所使用的系统上未附有AWK,可通过anonymous ftp 到下列地方取得:

phi./pub/gnu

ftp/UNIX/gnu

preppub/gnu

注解:一种编程语言,因其模式匹配语法而特别有用,通常用于数据检索和数据转换。一个GNU版本称为Gawk。



小案例

[houchangren@ebsdi-23260-oozie shell]$ cat  /etc/fstab
/dev/VolGroup00/LogVol00 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
/dev/VolGroup00/LogVol01 swap                    swap    defaults        0 0
[houchangren@ebsdi-23260-oozie shell]$ awk  '{print $0}'  /etc/fstab
/dev/VolGroup00/LogVol00 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                 /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
/dev/VolGroup00/LogVol01 swap                    swap   defaults        0 0
[houchangren@ebsdi-23260-oozie shell]$ awk  '{print}'  /etc/fstab
/dev/VolGroup00/LogVol00 /                       ext3    defaults        1 1
LABEL=/boot             /boot                   ext3    defaults        1 2
tmpfs                   /dev/shm                tmpfs   defaults        0 0
devpts                  /dev/pts                devpts  gid=5,mode=620  0 0
sysfs                   /sys                    sysfs   defaults        0 0
proc                    /proc                   proc    defaults        0 0
/dev/VolGroup00/LogVol01 swap                    swap    defaults        0 0
[houchangren@ebsdi-23260-oozie shell]$ awk  '{print $1}'  /etc/fstab
/dev/VolGroup00/LogVol00
LABEL=/boot
tmpfs
devpts
sysfs
proc
/dev/VolGroup00/LogVol01
[houchangren@ebsdi-23260-oozie shell]$ awk  '{print "I am test"}'  /etc/fstab
I am test
I am test
I am test
I am test
I am test
I am test
I am test
[houchangren@ebsdi-23260-oozie shell]$


在文件 /etc/fstab中有六列

Device 装置名称

MountPoint 挂入点

Fstype 挂入类型

Options 参数

Dump 备份标示

Pass检查顺序,fsck用

关于fstab详细可参考:

http://hi.baidu.com/iezunhfiybhiour/item/e0348e8ca7c6562e100ef3ce







awk解释:

awk 是默认逐行读取,I am test 打印了,对应的行,

print $0就等于 print

print $1就取第一列。





基本语法

多个字段
awk常常被用于处理字段。所谓字段,就是在文本文件中,每一行分成许多列,列与列之间

用特定的符一号隔开。awk在这方面的处理能力特别强。



[houchangren@ebsdi-23260-oozie shell]$ awk '{print $1}' /etc/fstab
/dev/VolGroup00/LogVol00
LABEL=/boot
tmpfs
devpts
sysfs
proc
/dev/VolGroup00/LogVol01
[houchangren@ebsdi-23260-oozie shell]$ awk '{print $1 "\t " $3}' /etc/fstab
/dev/VolGroup00/LogVol00         ext3
LABEL=/boot      ext3
tmpfs   tmpfs
devpts  devpts
sysfs   sysfs
proc    proc
/dev/VolGroup00/LogVol01         swap
[houchangren@ebsdi-23260-oozie shell]$ awk '{print "device:" $1 "\tfstype: " $3}' /etc/fstab
device:/dev/VolGroup00/LogVol00 fstype:ext3
device:LABEL=/boot      fstype: ext3
device:tmpfs    fstype: tmpfs
device:devpts   fstype: devpts
device:sysfs    fstype: sysfs
device:proc     fstype: proc
device:/dev/VolGroup00/LogVol01 fstype:swap
[houchangren@ebsdi-23260-oozie shell]$


指定列分隔符


[houchangren@ebsdi-23260-oozie data]$ cat pwd.piece
root:x:0:0:root:/root:/bin/bash
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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/etc/news:
#指定冒号作为分隔符
[houchangren@ebsdi-23260-oozie data]$ awk -F":" '{print "user:"$1 "\t shell:"$7}' pwd.piece
user:root        shell:/bin/bash
user:bin         shell:/sbin/nologin
user:daemon      shell:/sbin/nologin
user:adm         shell:/sbin/nologin
user:lp shell:/sbin/nologin
user:sync        shell:/bin/sync
user:shutdown    shell:/sbin/shutdown
user:halt        shell:/sbin/halt
user:mail        shell:/sbin/nologin
user:news       shell:
 
#多个字符作为分隔符
[houchangren@ebsdi-23260-oozie data]$ awk -F"[\t ]+" '{print "device:"$1 "\tfstype:"$3}'/etc/fstab
device:/dev/VolGroup00/LogVol00 fstype:ext3
device:LABEL=/boot      fstype:ext3
device:tmpfs    fstype:tmpfs
device:devpts   fstype:devpts
device:sysfs    fstype:sysfs
device:proc     fstype:proc
device:/dev/VolGroup00/LogVol01 fstype:swap
 
awk输入来源
[houchangren@ebsdi-23260-oozie data]$ head -5 /etc/passwd | awk -F":" '{print "user:"$1 "\tshell:"$7}'
user:root        shell:/bin/bash
user:bin         shell:/sbin/nologin
user:daemon      shell:/sbin/nologin
user:adm         shell:/sbin/nologin
user:lp shell:/sbin/nologin


awk命令并不管文本来自何方,准确地说,awk读取标准输入。

当你将文本文件作为参数传递给awk命令时,awk命令打开文本文件,将之作为标准输入传递给awk的主逻辑。



awk语言特性

很多在UNIX、Linux中浸淫许久的人都称awk为一门语言。这不仅仅是对awk的恭维,其实awk作为一门语言当之无愧。除了在前面提及的最简单的文本处理功能,awk还具有计算机语言所特有的性质,例如变量、判断、循环,甚至数组。



awk代码结构


begin和end



在awk处理数据之前和之后可以添加代码块begin和end





在begin块中设置了,分隔符是冒号,和打印提示。

在end块中打印了结束提示。

[houchangren@ebsdi-23260-oozie shell]$ cat awk/fs.awk
BEGIN{
FS=":"
print "I am begin!"
}
{
print "USER:" $1  "\tshell:" $7
}
END{
print "I am end!"
}
 
[houchangren@ebsdi-23260-oozie shell]$ head -5 /etc/passwd | awk -f awk/fs.awk
I am begin!
USER:root       shell:/bin/bash
USER:bin        shell:/sbin/nologin
USER:daemon     shell:/sbin/nologin
USER:adm        shell:/sbin/nologin
USER:lp shell:/sbin/nologin
I am end!
 
 
awk数据处理支持正则表达式如下
 
[houchangren@ebsdi-23260-oozie shell]$ cat awk/search.awk
BEGIN{
FS=":"
}
/nologin/ {++sum}
END{
print "'nologin' appears \t" sum  "\ttimes."
 
}
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/search.awk /etc/passwd
'nologin' appears       32     times.
 
 
//多项模式匹配
[houchangren@ebsdi-23260-oozie shell]$ cat awk/search.awk
BEGIN{
FS=":"
}
/nologin/ {++sum}
/bash/{ ++bashs}
END{
print "we have \t" sum  "\t nologin users"
print "we have \t " bashs"\t base  users"
}
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/search.awk /etc/passwd
we have         32       nologin users
we have          25      base users




变量与数组


变量

在awk中有两种变量

1. 用户自定义变量

2. 内建变量



变量只存储字符串,当需要时再转换为其他类型



awk的变量必须以ASCII字母或下划线开始,然后选择性地接上字毋、下划线及数字。如果

用正则表达式来匹配变量名的话,awk的变量名必须匹配[A-Za-z_][A-Za-z_0-9]*。

awk的变量名长度没有限制。

awk的变量名对大小写是敏感。



建议:

局部变量小写,全局变量第一个字母大写,内建变量全部大写。



Awk常用变量



属性
说明
$0
当前记录(作为单个变量)
$1~$n
当前记录的第n个字段,字段间由FS分隔
FS
输入字段分隔符 默认是空格
NF
当前记录中的字段个数,就是有多少列
NR
已经读出的记录数,就是行号,从1开始
RS
输入的记录分隔符默 认为换行符
OFS
输出字段分隔符 默认也是空格
ORS
输出的记录分隔符,默认为换行符
ARGC
命令行参数个数
ARGV
命令行参数数组
FILENAME
当前输入文件的名字
IGNORECASE
如果为真,则进行忽略大小写的匹配
ARGIND
当前被处理文件的ARGV标志符
CONVFMT
数字转换格式 %.6g
ENVIRON
UNIX环境变量
ERRNO
UNIX系统错误消息
FIELDWIDTHS
输入字段宽度的空白分隔字符串
FNR
当前记录数
OFMT
数字的输出格式 %.6g
RSTART
被匹配函数匹配的字符串首
RLENGTH
被匹配函数匹配的字符串长度
SUBSEP
\034
数组的使用无需声明即可使用。



数组



awk中的数组命名遵循了与变量命名相同的惯例,数组包含了从零到多个数据项,通过紧接着名称的数组索引选定。

大部分程序语言都需要以整数表达式作为索引的数组,但是awk允许在数组名称之后,以方括号将任意数字或字符串表达式括起来作为索引。



数组的元素类型可以为多种类型。

数组的存储空间是稀疏的,比如存储1,和10000索引的数组值,它不会自动填充它们之间的值的。







[houchangren@ebsdi-23260-oozieshell]$ cat awk/array.awk
BEGIN{
arr[0]=0;
arr[10000]=10000;
arr["baidu"]="www.baidu.com";
}
 
//
{
print"init:\t" arr["baidu"];
arr["baidu"]="www.baidu.cn";
print"modifyed:\t" arr["baidu"];
deletearr["baidu"];
print"deleted:\t" arr["baidu"];
 
}
 
END{
 
}
[houchangren@ebsdi-23260-oozieshell]$ echo "test" |awk -f awk/array.awk
test
init:   www.baidu.com
modifyed:       www.baidu.cn
deleted:
[houchangren@ebsdi-23260-oozieshell]$


环境变量操作

[houchangren@ebsdi-23260-oozie shell]$awk  'BEGIN{printENVIRON["HOME"];print ENVIRON["PATH"]}'
/home/houchangren
/usr/local/pig/pig-0.12.0/bin:/usr/java/jdk1.6.0_31/bin:/usr/maven3/bin/:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.6.0_31:/usr/apache-ant-1.9.2/bin:/usr/local/hive-0.7.1-cdh3u6/bin:/home/hbase/hbase-0.94.10/bin:/root/bin






算数运算和运算符
在awk中直接支持算术运算



[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print "3+5=" 3+5}'
3+5=8
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print "2^10=" 2^10}'
2^10=1024
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print "2*(5+10)=" 2*(5+10)}'
2*(5+10)=30






小例子(判断是闰年还是平年)



[houchangren@ebsdi-23260-oozie shell]$ cat awk/leap.awk
BEGIN{
print "Pick Your Leap Years";
}
/**app module*/
{
year =$1
if((year%4==0&&year %100!=0) ||year%400==0)
  print year " is leap year."
else
  print year "is not a leap year."
 
}
 
END{
print "shell end"
}
[houchangren@ebsdi-23260-oozie shell]$
 
[houchangren@ebsdi-23260-oozie shell]$ echo '2013' | awk -f awk/leap.awk;
Pick Your Leap Years
2013is not a leap year.
shell end
[houchangren@ebsdi-23260-oozie shell]$ echo '2000' | awk -f awk/leap.awk;
Pick Your Leap Years
2000 is leap year.
shell end


awk中的运算符



运算符
描述
用法
= += -= *= /= %= ^= **=
赋值语句
awk 'BEGIN{a=10;print a}'

awk 'BEGIN{a+=10;print a}'

awk 'BEGIN{a-=10;print a}'

awk 'BEGIN{a*=10;print a}'

awk 'BEGIN{a/=10;print a}'

awk 'BEGIN{a%=10;print a}'

awk 'BEGIN{a^=10;print a}'

awk 'BEGIN{a**=10;print a}'
?:
三元运算符
awk 'BEGIN{print (1==1)?"true":"false"}'
||
逻辑或
awk 'BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}'
&&
逻辑与
awk 'BEGIN{a=1;b=2;print (a>5 && b<=2),(a>5 || b<=2);}'
~ ~!
匹配正则表达式和

不匹配正则表达式
awk 'BEGIN{a="IamTest";if(a ~ /^Iam*/){print a;}else{print "....."}}'

awk 'BEGIN{a="IamTest";if(a ~! /^Iam*/){print a;}else{print "....."}}'
< <= > >= != ==
关系运算符
略.
+ - * / %
加减乘除和取余
略.
^ **
幂函数
awk 'BEGIN{print 10**10}'

awk 'BEGIN{print 10^10}'
++ --
加加和减减,

是自身修改,

分前缀和后缀
 
$
字段引用
echo "123123" |awk '{print $1}'
in
数组成员 判断 key是不是有
awk 'BEGIN{arr[0]="b";print(0 in arr)}'
判断和循环
Awk中的条件语句主要有if、else循环语句主要是for 和while



If实例

[root@ebsdi-23260-oozie ~]# awk 'BEGIN{a=1;b=2;if(a>b){print"大于";}else{print"小于";}}'
小于
 
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{a=1;b=2;if(a>b){print"大于";}elseif(a==1){print "a=1";}else{ print"小于";}}'
a=1
 
 
while循环
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{i=3;while(i>0){print i;i--}}'
3
2
1
Do while 循环
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{i=3;do{print i;i--}while(i>0)}'
3
2
1
 
For循环
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{for(i=3;i>0;i--){print i;}}'
3
2
1
 
Break中断循环
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{i=3;while(i>0){if(i==2)break;print i;i--}}'
3
 
Continue跳过本次循环
[root@ebsdi-23260-oozie ~]# awk 'BEGIN{for(i=3;i>0;i--){if(i==2)continue;print i;}}'
3
1


多行一条记录FS 和RS


在awk中除了有字段还有记录行的概念,默认情况下是一条行是一条记录,但是有时候一条记录可能跨多行。

如下

[houchangren@ebsdi-23260-oozie shell]$ cat data/boys.txt
Xiaoming
10
Beijing.china
 
Xiaohou
14
Shanghai.china
 
Lisha
13
Paris. France




在上文的awk变量中已经有表格说明了指定行RS和FS是记录分隔符和字段分隔符



[houchangren@ebsdi-23260-oozieshell]$ vim awk/boys.awk
BEGIN{
RS="";
FS="\n"
}
{
print$1 "\t" $2 "\t" $2
}
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/boys.awk  data/boys.txt
Xiaoming        10     10
Xiaohou 14      14
Lisha  13      13












设定ORS和OFS

[houchangren@ebsdi-23260-oozie shell]$ vim awk/boys.awk
 
BEGIN{
RS="";
FS="\n";
ORS="\n\n";
OFS=",";
 
}
{
print $1","$2","$3
}
 
[houchangren@ebsdi-23260-oozie shell]$ awk -f  awk/boys.awk  data/boys.txt
Xiaoming,10,Beijing.china
 
Xiaohou,14,Shanghai.china
 
Lisha,13,Paris. France
 
[houchangren@ebsdi-23260-oozie shell]$
 
[houchangren@ebsdi-23260-oozie shell]$ cat awk/boys.awk
BEGIN{
RS="";
FS="\n";
ORS="";
 
}
{
x=1
while(x<=NF){
print $x "\t"
x++
}
print "\n"
}
 
[houchangren@ebsdi-23260-oozie shell]$ awk -f  awk/boys.awk  data/boys.txt
Xiaoming        10     Beijing.china
Xiaohou 14      Shanghai.china
Lisha  13      Paris. France




用户自定义函数

格式


awk的用户自定义函数获取参数,选择性地返回标量值。函数可以定义在程序顶层的任意位置,定义的格式为:



function  functionName (args1,args2,….){
//code block
 
}




实例增加函数

[houchangren@ebsdi-23260-oozie shell]$ cat awk/fun_add.awk
function add(x,y,sum){
sum=x+y;
return sum;
}
BEGIN{
print "test function add";
m=2;
n=3;
x=add(m,n);
printf ("m:%d\n",m);
printf ("n:%d\n",n);
 
printf ("sum of m and n is%d",x);
 
print("\n");
 
}
 
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/fun_add.awk
test function add
m:2
n:3
sum of m and n is 5


参数引用
在awk中也有引用传递和值传递的一说

值引用(执行完swap函数后,值没变);

[houchangren@ebsdi-23260-oozie shell]$ vim awk/fun_swap.awk
 
function swap(x,y,temp){
temp=x;
x=y;
y=temp;
}
BEGIN {}
{
m=3;
n=2;
 
printf("m:%d-----------n:%d\n",m,n);
swap(m,n);
printf("m:%d-----------n:%d\n",m,n);
 
}
[houchangren@ebsdi-23260-oozie shell]$ echo "" |awk -f awk/fun_swap.awk
m:3-----------n:2
m:3-----------n:2


传递引用(执行完swap函数后,值变了);



[houchangren@ebsdi-23260-oozie shell]$ echo "" |awk -f awk/fun_swap2.awk
arr[0]:10-----arr[1]11
arr[0]:11-----arr[1]10
[houchangren@ebsdi-23260-oozie shell]$ vim awk/fun_swap2.awk
 
function swap(arr,temp){
 
temp=arr[0];
arr[0]=arr[1];
arr[1]=temp;
}
BEGIN{}
 
{
arr[0]=10;
arr[1]=11;
 
printf("arr[0]:%d-----arr[1]%d\n",arr[0],arr[1]);
swap(arr);
printf("arr[0]:%d-----arr[1]%d\n",arr[0],arr[1]);
 
 
 
}
 
[houchangren@ebsdi-23260-oozie shell]$ echo "" |awk -f awk/fun_swap2.awk
arr[0]:10-----arr[1]11
arr[0]:11-----arr[1]10


递归调用


[houchangren@ebsdi-23260-oozie shell]$ echo -e "1\n3\n5\n10\n20\n35\n40" |awk -f awk/fun_fibonacci.awk
------------
1th of fibonacci sequence is 1
------------
3th of fibonacci sequence is 2
------------
5th of fibonacci sequence is 5
------------
10th of fibonacci sequence is 55
------------
20th of fibonacci sequence is 6765
------------
35th of fibonacci sequence is 9227465
------------
40th of fibonacci sequence is 102334155




由于上方的斐波那契的算法,特别忙,当执行35时候就得20秒左右40的时候好像就得10分钟左右了。



优化程序改为下方



[houchangren@ebsdi-23260-oozie shell]$ vim awk/fun_fibonacci2.awk
 
ind =3'
ind++;
BEGIN{
function fibonacci(array,n,ind){
ind =3;
while(ind<=n){
array[ind]=array[ind-1]+array[ind-2];
ind++;
}
 
}
BEGIN{}
/**code block*/
{
array[1]=1;
array[2]=1;
n=$1;
fibonacci(array,n);
printf("%dth of  fibonacci sequence is :%d\n",n,array
);
 
}
 
 
 
[houchangren@ebsdi-23260-oozie shell]$ echo -e "1\n3\n5\n10\n20\n30\n35\n50" |awk -f awk/fun_fibonacci2.awk
1th of fibonacci sequence is : 1
3th of fibonacci sequence is : 2
5th of fibonacci sequence is : 5
10th of fibonacci sequence is : 55
20th of fibonacci sequence is : 6765
30th of fibonacci sequence is : 832040
35th of fibonacci sequence is : 9227465
50th of fibonacci sequence is : 12586269025








字符串和算术处理

格式化输出


[houchangren@ebsdi-23260-oozie shell]$ vim awk/print.awk
  
BEGIN{}
 
{
x=1;
b="foo";
printf("my name is %s,I'm%s\n","xiaohouzi",10);
myout=sprintf("%s=%s",b,x);
print myout;
}
 
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk -f awk/print.awk
my name is xiaohouzi,I'm 10
foo=1




在printf和sprintf中操作时一样的,不同的时候sprintf可以将输出写到变量中,为变量赋值而使用。





转义符
转移字符
解释
%c
单个字符
%s
字符串
%d
十进制有符号整数
%ld
十进制长整型
%u
十进制无符号整数
%lu
十进制无符号长整型数
%x
十六进制表示的整数
%lx
十六进制表示的长整数
%o
八进制整数
%lo
八进制长整数
%e
指数形式的浮点数
%f
浮点数
%g
选e或者f中较短的一种形式
\n
换行
\f
清屏并换页
\r
回车
\t
Tab符
\xhh
表示一个ASCII码用16进表示,

其中hh是1到2个16进制数
修饰符

字符

定义
-
左对齐修饰符
#
显示八进制的时候前边加个0,显示十六进制的时候前面加个0x
+
显示使用d,e,f和g转换的整数时,加上正负号+或者-
0
用0而不是空白符来填充所显示的值
实例


[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10s|\n","ollir");}';
|    ollir|
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10s|\n","hello,ollir");}';
|hello,ollir|
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%-10s|\n","hello");}';
|hello     |
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10.5g|\n","hello");}';
|        0|
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10.5g|\n","023");}';
|       23|
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10.5g|\n",23.4454);}';
|   23.445|
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk '{printf("|%10.5g|\n",23.445433);}';
|   23.445|
[houchangren@ebsdi-23260-oozie shell]$ echo "10, 6, 19.123232342346345" | awk '{printf("|%*.*g|\n",$1,$2,$3);}';
|  19.1232|




字符串函数




函数

说明
gsub( Ere, Repl, [ In ] )
除了正则表达式所有具体值被替代这点,它和 sub 函数完全一样地执行,。
sub( Ere, Repl, [ In ] )
用 Repl 参数指定的字符串替换 In 参数指定的字符串中的由 Ere 参数指定的扩展正则表达式的第一个具体值。sub 函数返回替换的数量。出现在 Repl 参数指定的字符串中的 &(和符号)由 In 参数指定的与 Ere 参数的指定的扩展正则表达式匹配的字符串替换。如果未指定 In 参数,缺省值是整个记录($0 记录变量)。
index( String1, String2 )
在由 String1 参数指定的字符串(其中有出现 String2 指定的参数)中,返回位置,从 1 开始编号。如果 String2 参数不在 String1 参数中出现,则返回 0(零)。
length [(String)]
返回 String 参数指定的字符串的长度(字符形式)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
blength [(String)]
返回 String 参数指定的字符串的长度(以字节为单位)。如果未给出 String 参数,则返回整个记录的长度($0 记录变量)。
substr( String, M, [ N ] )
返回具有 N 参数指定的字符数量子串。子串从 String 参数指定的字符串取得,其字符以 M 参数指定的位置开始。M 参数指定为将 String 参数中的第一个字符作为编号 1。如果未指定 N 参数,则子串的长度将是 M 参数指定的位置到 String 参数的末尾 的长度。
match( String, Ere )
在 String 参数指定的字符串(Ere 参数指定的扩展正则表达式出现在其中)中返回位置(字符形式),从 1 开始编号,或如果 Ere 参数不出现,则返回 0(零)。RSTART 特殊变量设置为返回值。RLENGTH 特殊变量设置为匹配的字符串的长度,或如果未找到任何匹配,则设置为 -1(负一)。
split( String, A, [Ere] )
将 String 参数指定的参数分割为数组元素 A[1], A[2], . . ., A
,并返回 n 变量的值。此分隔可以通过 Ere 参数指定的扩展正则表达式进行,或用当前字段分隔符(FS 特殊变量)来进行(如果没有给出 Ere 参数)。除非上下文指明特定的元素还应具有一个数字值,否则 A 数组中的元素用字符串值来创建。
tolower( String )
返回 String 参数指定的字符串,字符串中每个大写字符将更改为小写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
toupper( String )
返回 String 参数指定的字符串,字符串中每个小写字符将更改为大写。大写和小写的映射由当前语言环境的 LC_CTYPE 范畴定义。
sprintf(Format, Expr, Expr, . . . )
根据 Format 参数指定的 printf 子例程格式字符串来格式化 Expr 参数指定的表达式并返回最后生成的字符串。
实例:

字符串查找



[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{pos=index("hello,ollir","ollir");print pos;}'
7
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{pos=index("hello ,ollir","ollir");print pos;}'
9
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{pos=index("hello,ollir","ollirs");print pos;}'
0




自定义一个反向查询索引函数

[houchangren@ebsdi-23260-oozie shell]$ vim awk/rindex.awk
 
function rindex(string,find,k,ns,nf){
 
ns=length(string);
nf=length(find);
 
for(k=ns+1-nf;k>nf;k--){
 if(substr(string,k,nf)==find){
       return k;
    }
}
return 0;
}
BEGIN{}
 
{
string=$1;
find=$2;
 
printf("Reverse index of  %s in %s is :%d\n",find,string,rindex(string,find));
 
}
[houchangren@ebsdi-23260-oozie shell]$ echo "123456789012345 123" | awk -f awk/rindex.awk
Reverse index of  123 in 123456789012345 is :11








子字符串提取




[houchangren@ebsdi-23260-oozie shell]$ cat data/info.txt
1.first is lilei
2.second is liuhai
3.thrid is zhangsan
[houchangren@ebsdi-23260-oozie shell]$ awk '{print substr($1,3);}' data/info.txt
first
second
third
[houchangren@ebsdi-23260-oozie shell]$ awk '{print substr($3,0);}' data/info.txt
lilei
liuhai
zhangsan
[houchangren@ebsdi-23260-oozie shell]$ awk '{print substr($3,0,5);}' data/info.txt
lilei
liuha
zhang




字符串匹配






match函数提供了与正则匹配的操作。



awk除了返回子串的索引外,还有副作用:设置系统变量RSTART和RLENGTH。RSTART在match()函数运行后被设置为匹配上正则表达式的字符串的起始位置 , RLENGTH则被设置为匹配上正则表达式的子字符串的长度。如果无法完成匹配,则RSTART被设置为0,而RLENGTH被设置为-1。

[houchangren@ebsdi-23260-oozie shell]$ echo "" |awk '{start=match("this is a test",/[a-z]+$/);printstart;}'
11
[houchangren@ebsdi-23260-oozie shell]$ echo "" |awk '{start=match("this is a test",/[a-z]+$/);printstart "," RSTART "," RLENGTH;}'
11,11,4






子字符串替换



[houchangren@ebsdi-23260-oozie shell]$ echo "test is test" | awk '{gsub(/test/,"mytest");print}'
mytest is mytest
[houchangren@ebsdi-23260-oozie shell]$ echo "test is test" | awk '{sub(/test/,"mytest");print}'
mytest is test






大小写转换



[houchangren@ebsdi-23260-oozie shell]$ vim awk/translate.awk
{
printf("lower:%s\n",tolower($0));
printf("UPPER:%s\n",toupper($0));
}
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/translate.awk data/info.txt
lower:1.first  is lilei
UPPER:1.FIRST  IS LILEI
lower:2.second is liuhai
UPPER:2.SECOND IS LIUHAI
lower:3.thrid  is zhangsan
UPPER:3.THRID  IS ZHANGSAN


字符串分割

[houchangren@ebsdi-23260-oozie shell]$  awk 'BEGIN{info="this is atest";split(info,tA," ");print length(tA);for(k in tA){printk,tA[k];}}'
4
4 test
1 this
2 is
3 a


字符串重建




将数组中的元素连接成字符串

[houchangren@ebsdi-23260-oozie shell]$ vim awk/join.awk
function join (array,n,fs,k,s){
if( n >= 1 ){
 s=array[1];
 for(k=2;k<=n;k++)
   s=s fs array[k];
}
return s;
}
 
{
arr[1]="I";
arr[2]="am";
s=join(arr,2," ");
print s;
}
[houchangren@ebsdi-23260-oozie shell]$ echo "" | awk -f awk/join.awk
I am






算术函数


脚本经常处理报表所以算术函数是必须的。

Awk支持的算术函数



函数名

说明
atan2( y, x )
返回 y/x 的反正切。
cos( x )
返回 x 的余弦;x 是弧度。
sin( x )
返回 x 的正弦;x 是弧度。
exp( x )
返回 x 幂函数。
log( x )
返回 x 的自然对数。
sqrt( x )
返回 x 平方根。
int( x )
返回 x 的截断至整数的值。
rand( )
返回任意数字 n,其中 0 <= n < 1。
srand( [Expr] )
将 rand 函数的种子值设置为 Expr 参数的值,或如果省略 Expr 参数则使用某天的时间。返回先前的种子值。
常用函数

//pi的值
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print atan2(0,-1)}'
3.14159
//自然对数
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print exp(1)}'
2.71828
//exp的反函数
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print log(exp(1))}'
1
//平方根
[houchangren@ebsdi-23260-oozie shell]$ awk'BEGIN{print sqrt(2)}'
1.41421


取整函数


[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print int(100/3)}'
33
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print 100/3}'
33.3333
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print int(10.7)}'
10
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{printf("%f\n",10.7)}'
10.700000




随机数


关于随机数的原理参考:http://blog.csdn.net/johnhany/article/details/8106564





[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print rand(); srand();print rand();}'
0.237788
0.246611
[houchangren@ebsdi-23260-oozie shell]$ awk 'BEGIN{print rand(); srand();print rand();}'
0.237788
0.402041










部分信息参考



参考:http://www.cnblogs.com/chengmo/archive/2010/10/08/1845913.html





案例分析

生成数据报表


源数据

[houchangren@ebsdi-23260-oozie shell]$ cat data/sale.txt
GDD,9041,39,125288
CGDD,9042,4099,225759
CGDD,9043,4964.525,415723
CGDD,9047,1815.238,569063
CGDD,9053,59,326883
CGDD,9097,56,651912
CGDD,9098,39,953235
CGDD,9017,4099,982040
CGDD,9019,4964.525,1025987
CGDD,9018,1815.238,415723
 
[houchangren@ebsdi-23260-oozie shell]$ cat awk/sale.awk
#/usr/bin/awk -f
BEGIN{
FS=",";OFS="\t"
print"ORG_NAME\tJan\tFeb\tMar\t\tTotal";
print"---------------------------------------";
}
 
{$5 =$2 +$3 +$4}
{print$1"\t"$2"\t"$3"\t"$4"\t"$5}
{total2+=$2}
{total3+=$3}
{total4+=$4}
END{
print"---------------------------------------";
print "this is Jan total:"total2;
print "this is Feb total:"total3;
print "this is Mar total:"total4;
}
 
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/sale.awk data/sale.txt
ORG_NAME        Jan    Feb     Mar             Total
---------------------------------------
GDD    9041    39      125288 134368
CGDD   9042    4099    225759 238900
CGDD   9043    4964.525        415723 429731
CGDD   9047    1815.238        569063 579925
CGDD   9053    59     326883  335995
CGDD   9097    56      651912 661065
CGDD   9098    39      953235 962372
CGDD   9017    4099    982040 995156
CGDD   9019    4964.525        1025987 1.03997e+06
CGDD   9018    1815.238        415723 426556
                                0
---------------------------------------
this is Jan total:90475
this is Feb total:21950.5
this is Mar total:5691613


由于上表数据有点乱,下边修改一下脚本



[houchangren@ebsdi-23260-oozie shell]$ vim awk/sale.awk
 
#/usr/bin/awk -f
BEGIN{
FS=",";OFS="\t"
print"ORG_NAME\tJan\tFeb\tMar\t\tTotal";
print"---------------------------------------";
}
 
{$5 =$2 +$3 +$4}
{printf "%-8s%-10s%-10s%-10s%-20f\n",$1,$2,$3,$4,$5}
{total2+=$2}
{total3+=$3}
{total4+=$4}
END{
print "---------------------------------------";
print "this is Jan total:"total2;
print "this is Feb total:"total3;
print "this is Mar total:"total4;
}
~
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/sale.awk data/sale.txt
ORG_NAME        Jan    Feb     Mar             Total
---------------------------------------
GDD    9041      39        125288    134368.000000      
CGDD   9042      4099      225759   238900.000000      
CGDD   9043      4964.525  415723   429730.525000      
CGDD   9047      1815.238  569063   579925.238000      
CGDD   9053      59        326883    335995.000000      
CGDD   9097      56        651912    661065.000000      
CGDD   9098      39        953235    962372.000000      
CGDD   9017      4099      982040   995156.000000      
CGDD   9019      4964.525  1025987  1039970.525000     
CGDD   9018      1815.238  415723   426556.238000      
                                     0.000000           
---------------------------------------
this is Jan total:90475
this is Feb total:21950.5
this is Mar total:5691613






多文件联合处理




[houchangren@ebsdi-23260-oozie shell]$ cat data/stuff.txt
1      zhangsan
2      lisi
3      wangwu
6      maliu

[houchangren@ebsdi-23260-oozie shell]$ cat data/stuff_phone.txt
13522375325,zhangsan
18500193250,lisi
13421320433,wangwu
18923423443,maliu
 
[houchangren@ebsdi-23260-oozie shell]$ cat awk/stuffJoin.awk
BEGIN{
FS="[  |,]";
OFS=",";
}
NR<=FNR{
a[$2]=$1;
}
 
NR>FNR{
print $1,$2,a[$2]
}
 
 
END{}
 
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/stuffJoin.awk  data/stuff*
1,zhangsan,13522375325
2,lisi,18500193250
3,wangwu,13421320433
6,maliu,18923423443
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/stuffJoin.awk  data/stuff.txt data/stuff_phone.txt
13522375325,zhangsan,1
18500193250,lisi,2
13421320433,wangwu,3
18923423443,maliu,6




检验passwd的正确性


[houchangren@ebsdi-23260-oozie shell]$ cat data/passwd.datafile
root:x:0:0:root:/root:/bin/bash
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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/etc/news:
new:*:9:13:news:/etc/news:
halt:x:7:0:halt:/sbin:/sbin/halt:test
 
[houchangren@ebsdi-23260-oozie shell]$ vim awk/passwd.check.awk
 
BEGIN{
FS=":";
}
NF!=7{
printf("line %d,dose not have 7feilds:%s\n",NR,$0);
}
$1 !~ /[a-zA-z0-9]/{
printf("line %d,non alpha and numericuser id :%s\n",NR,$0);
}
$2=="*"{
printf("line %d,no password:%s\n",NR,$0);
}
 
END{}
[houchangren@ebsdi-23260-oozie shell]$ awk -f awk/passwd.check.awk data/passwd.datafile
line 11,nopassword:new:*:9:13:news:/etc/news:
line 12,dose not have 7feilds:halt:x:7:0:halt:/sbin:/sbin/halt:test


Sed/awk单行脚本
参考:

http://blog.chinaunix.net/uid-20718384-id-3296639.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: