shell_awk 更强大的文件操作

(转) 

  Linux awk几乎是一种自解释的独立编程语言。它的最基本的功能就是在文件和字符串中基于指定规则浏览和抽取信息。有三种方式可以调用awk,第一种是命令行方式,例如:

 

Java代码 复制代码  收藏代码
  1. awk [-F seperator-fields]  'commands' input-file  
awk [-F seperator-fields]  'commands' input-file

 

      commands是真正的awk命令,即由一系列的大括号组成,-F 域分割符 这个是可选的,awk默认采用空格来分割,但是对于/etc/passwd这样的文件,可能就需要采用冒号:  这样的分割符号。

 

      第二种方式是将所有的awk命令插入一个文件,并使awk程序可执行,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它

      第三种方式是将所有awk命令插入一个单独的文件,然后输入以下命令来调用: 

 

Java代码 复制代码  收藏代码
  1. awk -f awk-script-file input-files   
  2. //-f 选项指明在文件awk_script_file的awk脚本,input_file是使用awk进行浏览的文件名  
awk -f awk-script-file input-files
//-f 选项指明在文件awk_script_file的awk脚本,input_file是使用awk进行浏览的文件名

 

      awk语言中采取一种特别的方式来访问文件--域和记录

      awk执行的时候,将其浏览域标记为$1 $2 ... $n ,使用$1,$3表示将参考第一个域和第三个域,这里采用逗号来分隔开不同的域,如果希望打印全部的域,可以直接使用$0,而不必一个一个域的去指定。例如,打印/etc/passwd文件里的第一列(也即登录的用户名)

 

Java代码 复制代码  收藏代码
  1. awk -F :  '{ print $1 }' /etc/passwd  
awk -F :  '{ print $1 }' /etc/passwd

      将输出该文件的第一列

 

      任何awk语句都是由模式和动作来组成,模式部分决定动作语句何时触发及触发事件,处理即对数据采取的动作,如果省略模式,动作将时刻保持执行状态。

      模式可以是任意的正则表达式语句或其他条件语句,它包括两个特殊的字段,BEGIN和END,BEGIN使用在任何文本浏览动作之前,常用来打印行头,而END用在所有文本浏览动作之后,常用来打印文本总数和结尾状态标志。

      例如:有这样一个文件:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ cat grade.txt    
  2. chenwu 05/99 4811    
  3. mary   02/22 1231  
  4. tom    09/15 1182  
[chenwu@localhost unit9-awkIntroduce]$ cat grade.txt 
chenwu 05/99 4811 
mary   02/22 1231
tom    09/15 1182

 

       下面的语句将打印一个常用的报表头,及第一列和第三列。

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""id"} {print $1"\t"$3}' grade.txt    
  2. name    id   
  3. chenwu  4811  
  4. mary    1231  
  5. tom     1182  
[chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""id"} {print $1"\t"$3}' grade.txt 
name    id
chenwu  4811
mary    1231
tom     1182

       如果加上行尾,则应该是这样:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""id"} {print $1"\t"$3} END {print "end-of-report"}'    
  2. grade.txt >grade.report    
  3. [chenwu@localhost unit9-awkIntroduce]$ ls   
  4. grade.report  grade.txt   
  5. [chenwu@localhost unit9-awkIntroduce]$ cat grade.report    
  6. name    id   
  7. chenwu  4811  
  8. mary    1231  
  9. tom     1182  
  10. end-of-report  
[chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""id"} {print $1"\t"$3} END {print "end-of-report"}' 
grade.txt >grade.report 
[chenwu@localhost unit9-awkIntroduce]$ ls
grade.report  grade.txt
[chenwu@localhost unit9-awkIntroduce]$ cat grade.report 
name    id
chenwu  4811
mary    1231
tom     1182
end-of-report

 

     在碰到awk错误的时候,应该这样查找错误:

        1:查找命令commands是否被单引号括起来

        2:查找commands内大括号是否匹配

 

    尝试着加入条件判断:

    这里打印名称为mary的行.   使用if($x(第几列)~  正则表达式)  语句   

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""ID"} {if($1 ~/mary/) print $0}   
  2.  END {print "end-of-report"}' grade.txt    
  3. name    ID   
  4. mary   02/22 1231  
  5. end-of-report  
[chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {print "name""\t""ID"} {if($1 ~/mary/) print $0}
 END {print "end-of-report"}' grade.txt 
name    ID
mary   02/22 1231
end-of-report
 

    而取反的方式是if($1 !~ /mary/)

    在awk中组合条件语句与javascript很类似,都是使用||或者&& ,这与传统的shell -o 或者 -a 不同。

 

    同时在awk中提供了很多内置变量,可以方便的运用。常用的有以下几个:

    NF  域的个数   NR  已读记录的个数  FILENAME表示文件名

    例如:   

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk '{print NF,NR,$0} END{print FILENAME}' grade.txt    
  2. 3 1 chenwu 05/99 4811    
  3. 3 2 mary   02/22 1231  
  4. 3 3 tom    09/15 1182  
  5. grade.txt  
[chenwu@localhost unit9-awkIntroduce]$ awk '{print NF,NR,$0} END{print FILENAME}' grade.txt 
3 1 chenwu 05/99 4811 
3 2 mary   02/22 1231
3 3 tom    09/15 1182
grade.txt

 

    awk中域值的比较操作有以下两种方式:

    第一种方式,直接在条件表达式里硬编码:

     例如,想查看所有得分在27分以下的同学:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ cat grade.txt    
  2. chenwu 05/99 4811 27    
  3. mary   02/22 1231 30  
  4. tom    09/15 1182 25  
  5. [chenwu@localhost unit9-awkIntroduce]$ awk '{if($4<27) print $0}' grade.txt    
  6. tom    09/15 1182 25  
[chenwu@localhost unit9-awkIntroduce]$ cat grade.txt 
chenwu 05/99 4811 27 
mary   02/22 1231 30
tom    09/15 1182 25
[chenwu@localhost unit9-awkIntroduce]$ awk '{if($4<27) print $0}' grade.txt 
tom    09/15 1182 25

 

     这里还有第二种方式,在BEGIN模块里定义变量,从而可以提高内聚性。例如:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {baseline=27} {if($4<baseline) print $0}' grade.txt    
  2. tom    09/15 1182 25  
[chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {baseline=27} {if($4<baseline) print $0}' grade.txt 
tom    09/15 1182 25

 

    注意这里取变量的时候,不能加上$符号,如果不小心加上$baseline,那么什么都不会输出了:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {baseline=27} {if($4<$baseline) print $0}' grade.txt    
  2. [chenwu@localhost unit9-awkIntroduce]  
[chenwu@localhost unit9-awkIntroduce]$ awk 'BEGIN {baseline=27} {if($4<$baseline) print $0}' grade.txt 
[chenwu@localhost unit9-awkIntroduce]

 

     如果只是想统计某一列的总和等,则应该这样做:     

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ awk '{total+=$4} END {print "total scores are "total}' grade.txt    
  2. total scores are 82  
[chenwu@localhost unit9-awkIntroduce]$ awk '{total+=$4} END {print "total scores are "total}' grade.txt 
total scores are 82

 

     再例如,只查找所有普通文件的长度总和(非目录)。可以参考下面的方式:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ ls -l | awk 'BEGIN {total=0} {if($1~/^[^d]/) total+=$5;print $0}    
  2. END {print "total size:"total}'    
  3. 总计 12  
  4. -rw-rw-r-- 1 chenwu chenwu   53 06-10 10:16 grade.report   
  5. -rw-rw-r-- 1 chenwu chenwu   64 06-11 10:12 grade.txt   
  6. drwxrwxr-x 2 chenwu chenwu 4096 06-11 10:28 testDir   
  7. total size:117  
[chenwu@localhost unit9-awkIntroduce]$ ls -l | awk 'BEGIN {total=0} {if($1~/^[^d]/) total+=$5;print $0} 
END {print "total size:"total}' 
总计 12
-rw-rw-r-- 1 chenwu chenwu   53 06-10 10:16 grade.report
-rw-rw-r-- 1 chenwu chenwu   64 06-11 10:12 grade.txt
drwxrwxr-x 2 chenwu chenwu 4096 06-11 10:28 testDir
total size:117

 

      当然也可以将if($1 ~/^[^d]/) 换成if($1 ! ~ /^d/),例如:

 

Java代码 复制代码  收藏代码
  1. [chenwu@localhost unit9-awkIntroduce]$ ls -l | awk 'BEGIN {total=0} {if($1!~/^d/) total+=$5;print $0}    
  2. END {print "total size:"total}'    
  3. 总计 12  
  4. -rw-rw-r-- 1 chenwu chenwu   53 06-10 10:16 grade.report   
  5. -rw-rw-r-- 1 chenwu chenwu   64 06-11 10:12 grade.txt   
  6. drwxrwxr-x 2 chenwu chenwu 4096 06-11 10:28 testDir   
  7. total size:117  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值