awk详解

awk 'NR==1{print $1}' file
NR==1 定位在file的第一行
print $1 显示第一列内容

wKioL1M4xUKjLTRNAABpYxiX0XY484.jpg

awk -F":" 'NR==3,NR==5 {print $1}' /etc/passwd

打印/etc/passwd下3到5行的第一列


说到linux命令,大家都会了知一二,可以学linux最终极是很好的管理LINUX服务器,如同DBA一样,做一个LINUX系统管理员,LINUX命令了解程序决定了你的工资高低(当然Shell不在命令之外);

awk命令,做为查询命令的归类吧,这个命令应用非常的广泛,以至少于运算与分析上;所以,有必要学习,并通这学习这个命令,让你体验LINUX之强大;

  awk有三种调用方式:

  1,awk   -F"分隔符" "command" filename;

  2,将所有命令插入一个文件,使它权限程序可执行,然后当成脚本调用它;

  3,是将所有的awk命令插入一个单独文件,然后调用;如:awk -f awk-script-file  filename;

  字段的引用  $ 字段操作符;  $1代表第一列,$2代表第二列。。。n以此类推;  $0代表整个输入记录;

比较:cut -d" "  -f1sort -t" " -k1awk -F" " '{print $1}'

比较用cut和awk截取IP:

ifconfig eth0 |grep Bcast |cut -d ":" -f2|cut -d" " -f1

ifconfig eth0 |grep Bcast |awk -F: '{print $2}'|awk  '{print $1}'

ifconfig eth0 |grep Bcast | awk -F" " '{print $2}'|awk -F":" '{print $2}'

--awk默认以N个空格为分隔符;

打印所有行    awk '{print $0}' /etc/passwd

打印第一列  awk -F: '{print $1}' /etc/passwd

打印第一,三列  awk -F: '{print $1"\thaha\t"$3}' /etc/passwd

[root@li hyitao]# awk -F":" '{print $1" 的uid是 "$3}' /etc/passwd

[root@hy hyitao]# awk -F":" '{print $1"的uid是"$3",登录shell 是 "$7}' /etc/passwd

$n    n不一定要用整数,也可以用变量值代替

echo a b c |awk 'BEGIN {one=1;two=2} {print $(one+two)}'

格式:awk  -F:  ‘BEGIN {处理文件前执行的代码块} {处理文件过程中执行的代码块} END {处理文件后执行的代码块}'   filename

BEGIN {} {}END {

[root@hy hyitao]# awk -F: 'BEGIN {print "这是第一行"} {print $0} END {print "这是最后一行"}' /etc/passwd这是第一行,用awk打印表格结构如下:# echo | awk '{print "第一行"} { print "第二行"} { print "第三行"} {print "第四行"}'第一行第二行第三行第四行

root@li ~]# head -1 /etc/passwd  |awk -F: 'BEGIN {print "*************"} {print "*   "$1"    *"}{print "*   "$2"    *"}{print "*    "$3"   *"}{print "*    "$4"    *"}{print "*    "$5"    *"}{print "*    "$6"    *"}{print "*    "$7"    *"} END  {print "*************"}'

**************   root    **   x    **    0   **    0    **    root    **    /root    **    /bin/bash    **************--结果的对齐方面可以自己再去调整;


--awk  内置变量FS   设置分隔符,等同于-FNF   代表字段数$NF  代表最后一个字段数NR   代表当前处理第几行练习:用netstat -ntl 截取所有开放的端口号;

netstat -ntl |grep -v Active| grep -v Proto|awk '{print $4}'|awk -F: '{print $NF}'netstat -ntlup |grep -Ev "Active|Proto" |awk '{print $4}' |awk -F: '{print $NF}'

grep增强模式查找/etc/passwd里包含root或daemon的行cat /etc/passwd |grep -E "(root|daemon)"查找/etc/passwd里包含root或daemon或adm的行cat /etc/passwd |egrep "(root|adm|daemon)";

回顾上次的一个题目,把/etc下所有的.conf结尾的文件拷到一个目录,再改为.html结尾;不用rename,用awk来截;

[root@li ~]# find /etc/ -name "*.conf" |awk -F/ '{print $NF}' |awk -F".conf" '{print $1}打印第五行head -5 /etc/passwd |tail -1awk 'NR==5 {print $0}' /etc/passwd打印第五行的第五列head -5 /etc/passwd |tail -1 |cut -d":" -f5awk -F":" 'NR==5 {print $5}' /etc/passwd打印每一行的最后一列 awk -F: '{print $NF}' /etc/passwd 或者awk  '{FS=":"} {print $NF}' /etc/passwd  --第一行会打印出整行打印第五行awk 'NR==5 {print $0}' /etc/passwd 或者 awk '{if (NR==5) print $0}' /etc/passwd打印每行的字段数 awk  -F: '{print NF}' /etc/passwd打印第五行的字段数  awk  -F: 'NR==5 {print NF}' /etc/passwd打印最后一行awk -F: ' END {print $0} ' /etc/passwd打印最后一行的最后一列 awk -F: ' END {print $NF} ' /etc/passwd

或者:awk -F: '{a=$NF}END {print a} ' /etc/passwd


awk关系操作符==   等于!=    不等于>    大于<    小于>=   大于等于<=   小于等于

awk逻辑操作符&& 逻辑与| | 逻辑或! 非

awk运算操作符+ - * / %^  幂   比如:2的三次方  2^3   --/bin/bash里面求幂为2**3打印前五行 awk -F: 'NR<=5 {print $0}' /etc/passwd

打印五到十行,并在前面加上行号 # awk -F: 'NR>=5 && NR<=10 {print NR,$0}' /etc/passwd

打印奇数行 (删除偶数行)awk -F: 'NR%2==1 {print NR,$0}' /etc/passwd

打印偶数行 (删除奇数行)awk -F: 'NR%2==0 {print NR,$0}' /etc/passwd

删除五分之一的行(打印其五分之四的行,要求这五分之一的行号间隔平均)awk -F: 'NR%5!=1 {print NR,$0}' /etc/passwd

打印/etc/passwd里普通用户的行awk -F: '$3>=500 && $3!=65534 {print $0}' /etc/passwd

打印字段数大于6的行awk -F: 'NF>6 {print $0}' /etc/passwd

打印所有的列数的总和--提示:awk是由上往下一行一行的扫描,类似写shell脚本时的循环语句,在这里是自动循环--思路:先定义一个变量值为0,每扫一行,就加上那一行的列数(NF),最后打印出结果;

# awk -F: 'BEGIN {a=0} {a=a+NF} END {print a}' /etc/passwd

打印列数大于5的总行数

awk -F: 'BEGIN {a=0} { if (NF>5) a=a+1} END {print a}' /etc/passwd

综合运算  echo |awk '{print 10^2+(90-80)}

也可以进行浮点数运算 echo |awk '{print 10.9^2+(90.5-80.2)/3}'

例1:监控磁盘使用率,高于80%的找出来,输出警告,发送邮件给管理员:

df -h |grep -v 容量|awk '{print $1,$5}'|awk -F% '{print $1}' |while read  ado                used=`echo $a| awk '$2>80 {print $1" is used:" $2"% warning!!!!!!!"}'`                echo $used >> /tmp/used.txtdonemail root  < /tmp/used.txtdf -l |grep -v Filesystem |awk '{ if ($3*100/$2>80) print $1"使用率超过80%"}' | mail root例2:计算swap总量,使用量,剩余量,使用百分比,剩余百分比

格式要求为:total used free used% free%xxxxx xxxx xxxx xxx% xxx%

--提示:[root@dns shell04]# echo | awk '{print "第一行"} { print "第二行"} { print "第三行"}''第一行第二行第三行

# free |grep Swap |awk '{print "total\tused\tfree\tused%\tfree%"} {print $2"\t"$3"\t"$4"\t"$3*100/$2"%\t"$4*100/$2"%"} 'total   used    free    used%   free%4096564 0       4096564 0%      100%


--awk外部脚本脚本的结构BEGIN {}      {}END {}

例 :把 awk -F: '{print $1}' /etc/passwd 改成写外部脚本的形式:

BEGIN {        FS=":"}        {        print $1}

# awk -f 1.awk /etc/passwd

例:打印字段数大于5的总行数(用脚本写)

awk -F: 'BEGIN {c=0} {if (NF>5) {c=c+1}} END {print c}' /etc/passwd

BEGIN {     FS=":"     c=0}{         NF>5     --这两句用if来写的话  为:  if ( NF>5 )        { c=c+1 }            c=c+1}END {        print c

}

例:找出目录下的最大的文件和最小的文件,输出平均大小

思路: ls 有一个参数大写字母S,会把文件从大到小排序,排序后,最大文件就是第一行(NR=1),最小文件就是最后一行,平均大小为(累计总大小/NR);注意 grep -v 总计 这句如果是英文系统,就换成grep -v Total#vim 3.awk

BEGIN   {        total=0}        {        if (NR==1)        print "最大文件是:"$NF" 其大小为:"$5        total=total+$5}END     {        print "最小文件是:"$NF" 其大小为:"$5        print "所有文件平均大小为:"total/NR}

# ll -S |grep -v total |awk -f 3.awk 最大文件是:shell04.txt 其大小为:7245最小文件是:1.awk 其大小为:33所有文件平均大小为:2957.8

--awk字符匹配

==  完全精确匹配

~ 匹配!~   不匹配

完全匹配awk -F: '$1=="oo" {print $0}' /etc/passwd

部分匹配awk -F: '$1~"oo" {print $0}' /etc/passwdawk -F: '$1~/oo/ {print $0}' /etc/passwd

不匹配awk -F: '$1!="oo" {print $0}' /etc/passwdawk -F: '$1!~"oo" {print $0}' /etc/passwd

例:统计/etc/passwd里以/sbin/nologin结束的用户名,把用户名打印出来,并统计个数

--非awk的用法,两条命令

cat /etc/passwd |grep nologin$ |cut -d":" -f1  --打印cat /etc/passwd |grep nologin$ |cut -d":" -f1 |wc -l --统计个数

#cat /etc/passwd |awk -F: 'BEGIN {a=0} { if ($7=="/sbin/nologin") {print $1; a=a+1} } END {print "其总个数为"a}'

例:倒序排序所有字段(/etc/passwd)

BEGIN {        FS=":"}{        for (i=NF;i>0;i--){                if (i != 1) {                        printf("%s%s",$i,FS)                }                else {                        printf ("%s",$i)                }                }                printf ("\n")}END {}

调用: awk -f awk07.awk /etc/passwd可以看到结果倒序排列;

如上面所有例子,都很有代表性,在实践中,我们会灵活运用,给你们经验一句:能简则简,能精则精,层层相包,从大到小!




awk 用法:awk ' pattern {action} '  

变量名 含义
ARGC 命令行变元个数
ARGV 命令行变元数组
FILENAME当前输入文件名
FNR 当前文件中的记录号
FS 输入域分隔符,默认为一个空格
RS 输入记录分隔符
NF 当前记录里域个数
NR 到目前为止记录数
OFS 输出域分隔符
ORS 输出记录分隔符

1、awk '/101/'               file 显示文件file中包含101的匹配行。
  awk '/101/,/105/'         file
  awk '$1 == 5'             file
  awk '$1 == "CT"'          file 注意必须带双引号
  awk '$1 * $2 >100 '       file  
  awk '$2 >5 && $2<=15'     file
2、awk '{print NR,NF,$1,$NF,}' file 显示文件file的当前记录号、域数和每一行的第一个和最后一个域。
  awk '/101/ {print $1,$2 + 10}' file 显示文件file的匹配行的第一、二个域加10。
  awk '/101/ {print $1$2}'  file
  awk '/101/ {print $1 $2}' file 显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
3、df | awk '$4>1000000 '         通过管道符获得输入,如:显示第4个域满足条件的行。
4、awk -F "|" '{print $1}'   file 按照新的分隔符“|”进行操作。
  awk  'BEGIN { FS="[: \t|]" }
  {print $1,$2,$3}'      file 通过设置输入分隔符(FS="[: \t|]")修改输入分隔符。

  Sep="|"
  awk -F $Sep '{print $1}'  file 按照环境变量Sep的值做为分隔符。    
  awk -F '[ :\t|]' '{print $1}' file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
  awk -F '[][]'    '{print $1}' file 按照正则表达式的值做为分隔符,这里代表[、]
5、awk -f awkfile      file 通过文件awkfile的内容依次进行控制。
  cat awkfile
/101/{print "\047 Hello! \047"} --遇到匹配行以后打印 ' Hello! '.\047代表单引号。
{print $1,$2}                   --因为没有模式控制,打印每一行的前两个域。
6、awk '$1 ~ /101/ {print $1}' file 显示文件中第一个域匹配101的行(记录)。
7、awk   'BEGIN { OFS="%"}
  {print $1,$2}'           file 通过设置输出分隔符(OFS="%")修改输出格式。
8、awk   'BEGIN { max=100 ;print "max=" max}             BEGIN 表示在处理任意行之前进行的操作。
  {max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得文件第一个域的最大值。
  (表达式1?表达式2:表达式3 相当于:
  if (表达式1)
      表达式2
  else
      表达式3
  awk '{print ($1>4 ? "high "$1: "low "$1)}' file  
9、awk '$1 * $2 >100 {print $1}' file 显示文件中第一个域匹配101的行(记录)。
10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行后先将第3个域替换后再显示该行(记录)。
   awk '{$7 %= 3; print $7}'  file 将第7域被3除,并将余数赋给第7域再打印。
11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行后为变量wage赋值并打印该变量。
12、awk '/tom/ {count++;}  
        END {print "tom was found "count" times"}' file END表示在所有输入行处理完后进行处理。
13、awk 'gsub(/\$/,"");gsub(/,/,""); cost+=$4;
        END {print "The total is $" cost>"filename"}'    file gsub函数用空串替换$和,再将结果输出到filename中。
   1 2 3 $1,200.00
   1 2 3 $2,300.00
   1 2 3 $4,000.00

   awk '{gsub(/\$/,"");gsub(/,/,"");
   if ($4>1000&&$4<2000) c1+=$4;
   else if ($4>2000&&$4<3000) c2+=$4;
   else if ($4>3000&&$4<4000) c3+=$4;
   else c4+=$4; }
   END {printf  "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
   通过if和else if完成条件语句

   awk '{gsub(/\$/,"");gsub(/,/,"");
   if ($4>3000&&$4<4000) exit;
   else c4+=$4; }
   END {printf  "c1=[%d];c2=[%d];c3=[%d];c4=[%d]\n",c1,c2,c3,c4}"' file
   通过exit在某条件时退出,但是仍执行END操作。
   awk '{gsub(/\$/,"");gsub(/,/,"");
   if ($4>3000) next;
   else c4+=$4; }
   END {printf  "c4=[%d]\n",c4}"' file
   通过next在某条件时跳过该行,对下一行执行操作。


14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式为
   打印文件并前置文件名。
15、awk ' $1!=previous { close(previous); previous=$1 }    
   {print substr($0,index($0," ") +1)>$1}' fileall 把合并后的文件重新分拆为3个文件。并与原文件一致。
16、awk 'BEGIN {"date"|getline d; print d}'         通过管道把date的执行结果送给getline,并赋给变量d,然后打印。  
17、awk 'BEGIN {system("echo \"Input your name:\\c\""); getline d;print "\nYour name is",d,"\b!\n"}'
   通过getline命令交互输入name,并显示出来。
   awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'
   打印/etc/passwd文件中用户名包含050x_的用户名。

18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file 通过while语句实现循环。
   awk '{ for(i=1;i<NF;i++) {print NF,$i}}'   file 通过for语句实现循环。    
   type file|awk -F "/" '
   { for(i=1;i<NF;i++)
   { if(i==NF-1) { printf "%s",$i }
   else { printf "%s/",$i } }}'               显示一个文件的全路径。
   用for和if显示日期
   awk  'BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
 printf "\n%d月份\n",j;
       for(i=1;i<=31;i++)
       {
       if (j==2&&i>28) flag=1;
       if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
       if (flag==0) {printf "%02d%02d ",j,i}
       }
}
}'
19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
Flag=abcd
awk '{print '$Flag'}'   结果为abcd
awk '{print  "$Flag"}'   结果为$Flag

你可能感兴趣的:(awk详解)