`
qindongliang1922
  • 浏览: 2149463 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
7265517b-f87e-3137-b62c-5c6e30e26109
证道Lucene4
浏览量:116385
097be4a0-491e-39c0-89ff-3456fadf8262
证道Hadoop
浏览量:124644
41c37529-f6d8-32e4-8563-3b42b2712a50
证道shell编程
浏览量:58555
43832365-bc15-3f5d-b3cd-c9161722a70c
ELK修真
浏览量:70429
社区版块
存档分类
最新评论

跟散仙学shell编程(十二)

阅读更多
上篇文章散仙写了关于sed进阶,本篇我们来看下在linux中另外一种非常强大的文本处理语言gawk,有关于gawk的基础,散仙在前2篇文章,也有介绍,不熟悉的朋友,可以再回顾下。


gawk是一门功能丰富的编程语言,允许你通过编写高级程序来处理数据,只要我们有其他编程语言的经验,不管死JAVA,C#,Python,shell还是javascript,入手gawk都会感到非常亲切和容易。



下面来看下gawk里面的变量,在gawk里面总共有2种不同的变量,第一种是自带变量,第二种是自定义变量,下面来看下具体的几个常用的变量:

序号gawk自带变量名描述
1FIELDWIDTS由空格分隔开的定义了每个数据字段确切宽度的一列数字
2FS输出字段分隔符
3RS输入数据的行分隔符
4OFS输出字段分隔符
5ORS输出数据行分隔符


变量FS和OFS定义了gawk如何处理数据流中的数据字段,默认情况下gawk将OFS设置成一个空格:

[search@h1 822]$ gawk   '{print $1,$2,$3}' b.txt 
a b c
solr hadoop lucene
[search@h1 822]$ cat b.txt 
a b c
solr hadoop lucene
[search@h1 822]$ gawk   '{print $1,$2,$3}' b.txt 
a b c
solr hadoop lucene
[search@h1 822]$ gawk   '{print $1,$2}' b.txt    
a b
solr hadoop
[search@h1 822]$ 

输出字段分隔符:
[search@h1 822]$ cat b.txt 
a b c
solr hadoop lucene
[search@h1 822]$ gawk  'BEGIN{FS=" ";OFS="-"} {print $1,$2,$3 }' b.txt 
a-b-c
solr-hadoop-lucene
[search@h1 822]$ gawk  'BEGIN{FS=" ";OFS="--"} {print $1,$2,$3 }' b.txt 
a--b--c
solr--hadoop--lucene
[search@h1 822]$ gawk  'BEGIN{FS=" ";OFS="-->"} {print $1,$2,$3 }' b.txt 
a-->b-->c
solr-->hadoop-->lucene
[search@h1 822]$ 



下面看FIELDWIDTHSB变量,它会按固定的位数分隔,但是对于变长的字段就不适合了
[search@h1 822]$ cat c.txt 
1003455
1234522
2222222
5678890
[search@h1 822]$ gawk 'BEGIN{FIELDWIDTHS="2 3 2"}{print $1,$2,$3}' c.txt 
10 034 55
12 345 22
22 222 22
56 788 90
[search@h1 822]$ 


下面看行分隔符的使用:
[search@h1 822]$ cat cc 
中国 河南 洛阳1
电话 2522252




中国 河南 洛阳2
电话 2522252




中国 河南 洛阳3
电话 2522252
[search@h1 822]$ gawk  'BEGIN{FS="\n"; RS=""}  {print $1,$2}' cc  
中国 河南 洛阳1 电话 2522252
中国 河南 洛阳2 电话 2522252
中国 河南 洛阳3 电话 2522252
[search@h1 822]$ 


分析下流程,上述的例子里面我们把FS的分隔符设置为换行符,这说明gawk会把整个行当做一个字段,然后我们又把行分隔符设置为空格,然后再数据行间留一个空白行,gawk会把一个空行当成一个分隔符

除了上面的分隔符变量外,gawk里面还有一些其他的变量:

ARGC  当前命令行的个数
ARGIND 当前文件再ARGV里面的位置
ARGV   包含命令行参数的数组
FNR    当前数据文件中的数据行数
NF     数据文件里字段总数

[search@h1 822]$ gawk  'BEGIN{print ARGC,ARGV[1]}' cc 
2 cc
[search@h1 822]$ 


ARG变量表明命令行有两个参数,这包括gawk命令和cc参数,第一个数组值是gawk命令后的第一个命令行参数

[search@h1 822]$ gawk  'BEGIN{print ENVIRON["HOME"] ;   print ENVIRON["PATH"] } '
/home/search
.:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/jdk/bin:/home/search/hadoop/bin:/home/search/hadoop/sbin:/usr/local/ant/bin:/usr/local/maven/bin:/home/search/hive/bin:/home/search/hive/conf:/home/search/bin
[search@h1 822]$ 


ENVIRON命令可以从SHELL的变量里,提取值,但它使用的是字符串,不是索引来标识。
[search@h1 822]$ gawk  'BEGIN{FS=":"; OFS=":"} {print $1,$NF}' /etc/passwd
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin
adm:/sbin/nologin
lp:/sbin/nologin
sync:/bin/sync
shutdown:/sbin/shutdown
halt:/sbin/halt
mail:/sbin/nologin
uucp:/sbin/nologin
operator:/sbin/nologin
games:/sbin/nologin
gopher:/sbin/nologin
ftp:/sbin/nologin
nobody:/sbin/nologin
vcsa:/sbin/nologin
saslauth:/sbin/nologin
postfix:/sbin/nologin
sshd:/sbin/nologin
mysql:/bin/bash
search:/bin/bash
[search@h1 822]$ 



NF变量允许你指定数据行里最后一个字段,而不需要知道到底有多少个字段

[search@h1 822]$ cat c.txt 
1003455
1234522
2222222
5678890
[search@h1 822]$ gawk  'BEGIN{FS=","} {print $1, "FNR="FNR}' c.txt 
1003455 FNR=1
1234522 FNR=2
2222222 FNR=3
5678890 FNR=4
[search@h1 822]$ 


FNR变量含有当前处理过数据行的总数,NR变量含有所有的总数
[search@h1 822]$ cat c.txt 
1003455
1234522
2222222
5678890
[search@h1 822]$ gawk  'BEGIN{FS=","} {print $1, "FNR="FNR}' c.txt 
1003455 FNR=1
1234522 FNR=2
2222222 FNR=3
5678890 FNR=4
[search@h1 822]$ gawk  'BEGIN{FS=","} {print $1, "FNR="FNR, "NR="NR}' c.txt 
1003455 FNR=1 NR=1
1234522 FNR=2 NR=2
2222222 FNR=3 NR=3
5678890 FNR=4 NR=4
[search@h1 822]$ gawk  'BEGIN{FS=","} {print $1, "FNR="FNR, "NR="NR}' c.txt c.txt 
1003455 FNR=1 NR=1
1234522 FNR=2 NR=2
2222222 FNR=3 NR=3
5678890 FNR=4 NR=4
1003455 FNR=1 NR=5
1234522 FNR=2 NR=6
2222222 FNR=3 NR=7
5678890 FNR=4 NR=8
[search@h1 822]$ 



下面看下如何在gawk里面,使用自定义变量:
[search@h1 822]$ gawk  'BEGIN{test="你好,哈喽"; print test}'
你好,哈喽
[search@h1 822]$ 

[search@h1 822]$ gawk  'BEGIN{test="你好,哈喽"; print test ; test=123; print test}'
你好,哈喽
123
[search@h1 822]$ 


已经使用的变量可以再次使用。

也可以在gawk里面使用算术表达式
[search@h1 822]$ gawk  'BEGIN{x=4; x=x * 2 + 3 ; print x}'
11
[search@h1 822]$ 



还可以在命令端输出参数:
[search@h1 822]$ cat c.txt 
1003455
1234522
2222222
5678890
[search@h1 822]$ gawk  -f script n=1 c.txt  
1003455
1234522
2222222
5678890
[search@h1 822]$ cat script 
BEGIN{FS=","}
{print $n}
[search@h1 822]$ 

[search@h1 822]$ gawk  -f s2  n=1 c.txt 
这个数值: 
1003455
1234522
2222222
5678890
[search@h1 822]$ cat c.txt 
1003455
1234522
2222222
5678890
[search@h1 822]$ cat s2
BEGIN{ print "这个数值: "; n; FS="."}
{ print $n }
[search@h1 822]$ 

如果是在BEGIN前定义的变量,可能不会解析出来,我们需要加上-v参数

在gawk里面我们也可以很方便的使用数组变量:

[search@h1 822]$ gawk  'BEGIN{ a["key"]="value" ; print a["key"]}'
value
[search@h1 822]$ 



遍历数组也可以用我们最熟悉的foreach的方式:

[search@h1 822]$ gawk  'BEGIN{ a["1"]="aa"; a["2"]="ab" ; a["3"]="ac" ; for (t in a){ print "索引: ",t,"  值: ", a[t]  }  }'   
索引:  1   值:  aa
索引:  2   值:  ab
索引:  3   值:  ac
[search@h1 822]$ 

删除一个数组变量用delete命令:
[search@h1 822]$ gawk  'BEGIN{ a["1"]="aa"; a["2"]="ab" ; a["3"]="ac" ;  delete a["2"] ;  for (t in a){ print "索引: ",t,"  值: ", a[t]  }  }'
索引:  1   值:  aa
索引:  3   值:  ac
[search@h1 822]$ 



下面如何使用正则表达式结合gawk

[search@h1 822]$ cat a.txt 
data11
data22
data111

data4561
[search@h1 822]$ gawk 'BEGIN{FS=","} /11/{print $1} ' a.txt 
data11
data111
[search@h1 822]$ 



下面看下匹配操作符:


[search@h1 822]$ cat a.txt 
data11  test11  bbb111
data22  kkk222  ccc222
data111 ggg     jjjj

data4561 111    3333
[search@h1 822]$ gawk  'BEGIN{FS=" "} $2 ~ /^kk/{ print $0 }' a.txt 
data22  kkk222  ccc222
[search@h1 822]$ gawk  'BEGIN{FS=" "} $1 ~ /1/{ print $0 }' a.txt     
data11  test11  bbb111
data111 ggg     jjjj
data4561 111    3333
[search@h1 822]$ gawk  'BEGIN{FS=" "} $1 ~ /^1/{ print $0 }' a.txt 
[search@h1 822]$ gawk  'BEGIN{FS=" "} $1 ~ /^11/{ print $0 }' a.txt 
[search@h1 822]$ gawk  'BEGIN{FS=" "} $1 ~ /11/{ print $0 }' a.txt  
data11  test11  bbb111
data111 ggg     jjjj
[search@h1 822]$ 



$n ~ 可以指定在某个列里面进行查询过滤

!号可以排序,正则的过滤:
[search@h1 822]$ cat a.txt 
data11  test11  bbb111
data22  kkk222  ccc222
data111 ggg     jjjj

data4561 111    3333
[search@h1 822]$ gawk  'BEGIN{FS=" "} $1 !~ /11/{ print $0 }' a.txt  
data22  kkk222  ccc222

data4561 111    3333
[search@h1 822]$ 


数学表达式:
[search@h1 822]$ cat x.txt 
1 solr
2 lucne
3 hadoop 
1 solr2`
[search@h1 822]$ gawk '$1 == 1 { print $0 }' x.txt 
1 solr
1 solr2`
[search@h1 822]$ 


也可以比较文本:
[search@h1 822]$ cat x.txt 
1 solr
2 lucne
3 hadoop 
1 solr2`
[search@h1 822]$ gawk '$1 == 1 { print $0 }' x.txt 
1 solr
1 solr2`
[search@h1 822]$ gawk '$2 == "hadoop" { print $0 }' x.txt   
3 hadoop 
[search@h1 822]$ 



下面看下在gawk里面的结构化编程:
[search@h1 822]$ cat d1 
10
100
20
45
1
-11
[search@h1 822]$ gawk  '{ if ( $1 > 10 )  print $1} ' d1   
100
20
45
[search@h1 822]$ 


下面看下 if-else的例子:
[search@h1 822]$ cat d1 
10
100
20
45
1
-11
[search@h1 822]$ gawk  '{ if ( $1 > 10 )  print $1} ' d1   
100
20
45
[search@h1 822]$ gawk  '{ if ( $1 > 10 ) { print $1} else {  print "这里面小于10"  } } ' d1  
这里面小于10
100
20
45
这里面小于10
这里面小于10
[search@h1 822]$ 


下面看下while语句:


[search@h1 822]$ gawk  'BEGIN{ a=4; while (a<10){ a++ ; print a} }'
5
6
7
8
9
10
[search@h1 822]$ 


gawk支持在while里使用break和continue关键字:
[search@h1 822]$ gawk  'BEGIN{ a=4; while (a<10){ a++ ; if(a==9){ break ;} if (a==7){ continue;}    print a} }'      
5
6
8
[search@h1 822]$ 


下面看下for语句:


[search@h1 822]$ gawk  'BEGIN{ for(i=1;i<=10;i++) {  print "当前的值:"i }}'   
当前的值:1
当前的值:2
当前的值:3
当前的值:4
当前的值:5
当前的值:6
当前的值:7
当前的值:8
当前的值:9
当前的值:10
[search@h1 822]$ 


使用起来,非常顺手

gawk还支持格式化输出printf命令


gawk还支持一些常用的内置函数:
cos(x) 余弦
log(x)对数
rand() 比0大比1小的随机浮点值
[search@h1 822]$ gawk  'BEGIN{ x=10 * rand() ; print x}'
2.37788


除此之外,还有一些字符串函数,有过其他编程基础的人,很容易看明白下面的函数
length(s)取字符串长度
split()按某个符号拆分
asort()排序
match()匹配子串
tolower()转小写
toupper()转大写
等等

下面看下时间函数:

mktime(datespec)将一个按YYYY-MM-DD HH MM SS 格式转换时间错

strftime(format,[timestamp]) 格式化日期

systime() 返回当前的时间戳
[search@h1 822]$ gawk  'BEGIN{ print systime()}'
1408741666
[search@h1 822]$ 


下面看下自定义函数:

[search@h1 822]$ gawk  ' function m(){ print "我是自定义的方法" } BEGIN{    m(); }'
我是自定义的方法
[search@h1 822]$ 


需要注意的是函数名是唯一的


最后看下,如何在gawk自定义一些函数库:

[search@h1 822]$ cat ak 


function  a(){

print  "我是自定义的库"

}


function  b(i){


 for( b=i;b<10;b++){

print "我是自定义的第二个方法: "b
}

}



function c(){


print  rand()

}
[search@h1 822]$ cat ax
BEGIN{  a()  }
[search@h1 822]$ cat axx 
BEGIN{  c();  } 
[search@h1 822]$ gawk  -f ak -f ax
我是自定义的库
[search@h1 822]$ gawk  -f ak -f axx 
0.237788
[search@h1 822]$


我们不能直接在shell终端上使用库函数,但是我们可以用多个-f命令执行多个文件;
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics