awk方面对于初学者来说最难的是结构问题,看不懂结构,那就要面对大量的语法syntax报错(我的感觉)
首先一个例子
[vagrant@amainst perltest]$ ls -lt
total 64
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 testfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 fzonefile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 test.pl
对于以上数据,我要第3行的other的权限是多少,我怎么弄出来呢?
管道组合是最快的
#加个tail -n +2从第二行开始输出
[vagrant@amainst perltest]$ ls -lt|tail -n +2
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 testfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 fzonefile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 test.pl
#加个sed -n '3'p打印第三行
[vagrant@amainst perltest]$ ls -lt|tail -n +2|sed -n '3'p
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 fzonefile
#加个awk '{print $1}'显示第一域(我不说列,在awk里对于有分隔符的数据,统称域field,不称列column)
[vagrant@amainst perltest]$ ls -lt|tail -n +2|sed -n '3'p|awk '{print $1}'
-rwxrwxrwx.
#加个cut -c 8-10截取8-10位的字符
[vagrant@amainst perltest]$ ls -lt|tail -n +2|sed -n '3'p|awk '{print $1}'|cut -c 8-10
rwx
但如果用awk来呢
[vagrant@amainst perltest]$ ls -lt|awk 'NR==4{split($1,a,"");for(i=8;i<=10;i++){if(i==10){printf("%s\n",a[i])}else{printf("%s",a[i])}}}'
rwx
是不是感觉天书了
分行来分析一下结构
[vagrant@amainst perltest]$ ls -lt|awk 'NR==4{split($1,a,"")#首先是awk的pattern里进行了一个判断NR==4,这里我写在了外面,匹配的是第四行。然后第四行的第一域用split分割成数组a,分隔符是空,就是按字符分隔split($1,a,""),要注意的是awk里数组的下标默认是从1开始。
> for(i=8;i<=10;i++)#由于awk里没有a[8-10]这种数组截取的写法,这里写了个循环
> {if(i==10){printf("%s\n",a[i])}#在循环里判断是否是数组10,如果是10,就需要输出的时候带上回车符
> else{printf("%s",a[i])}
> }
> }'
rwx
拆掉每个分支的声明。结果如下
awk '{if(判断式){
干啥{
这里有个循环{
这里还有个if分支(判断式){
真的情况
}else{
假的情况}
}
}
}
}'
这样就可以更容易理解其结构
接下来就说awk的替换了,我之前一直很少用awk的替换原因之一就是还不懂awk的结构,替换的道理用的却是sed的思维,即sed 's/pattern1/pattern2/'。
弄清楚awk的结构以后替换就更容易理解一点。以下,我替换fzonefile为chmyfile。用sed和awk对比
[vagrant@amainst perltest]$ ls -lt|sed 's/fzonefile/chmyfile/'
total 64
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 testfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 chmyfile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 test.pl
[vagrant@amainst perltest]$ ls -lt|awk '{if($NF=="fzonefile"){sub("fzonefile","chmyfile",$NF)};print}'
total 64
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 testfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 chmyfile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 test.pl
分析awk这个结构
[vagrant@amainst perltest]$ ls -lt|awk '{if($NF=="fzonefile"){sub("fzonefile","chmyfile",$NF)}#当最后一域为fzonefile的时候,用sub方法替换fzonefile为chmyfile
> print}'#打印出全部内容,这个不在前一行的if分支里
total 64
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 testfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 chmyfile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 test.pl
有什么作用,因为我以前一直有个误区,用以下命令举例
[vagrant@amainst perltest]$ ls -lt|awk '/fzonefile/{sub("fzonefile","chmyfile",$NF);print}'
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 chmyfile
为什么只显示了一行的结果呢?
因为你的awk ’/pattern/‘里就只有一个if判断(用/关键字匹配/),所以print显示的结果自然只有一行,这就没了sed的功能。
那以上那么多废话以后,我怎么不傻瓜化的就用sed去完成我所有的替换需求呢?
因为sed的内判断循环问题一时还没掌握,先用awk来试试看。
例如,替换文本中test为new,但是不替换带bak的字符串
[vagrant@amainst perltest]$ ls -lt |awk '{if($NF~/test/&&$NF!~/bak/){sub("test","new",$NF)};print}'
total 64
-rw-rw-r--. 1 vagrant vagrant 292 Mar 24 13:51 newfile
-rw-rw-r--. 1 vagrant vagrant 48894 Mar 21 11:11 testfile.bak
-rwxrwxrwx. 1 vagrant vagrant 332 Mar 20 15:13 fzonefile
-rw-rw-r--. 1 vagrant vagrant 204 Mar 20 14:37 result
-rw-rw-r--. 1 vagrant vagrant 66 Mar 15 15:47 new.pl
网友评论