awk讲解步骤

来源:互联网 发布:淘宝自动核对地址 编辑:程序博客网 时间:2024/06/09 23:53

awk

语法
awk [options] ‘commands’ files
option
-F 定义字段分隔符,默认的分隔符是连续的空格或制表符
使用option中的-F参数定义间隔符号
1,2,$3等的顺序表示files中每行以间隔符号分隔的各列不同域
NF变量表示当前记录的字段数
-v 定义变量并赋值 也可以借用次方式从shell变量中引入

command    读前处理 行处理 读后处理    1.读前处理 BEGIN{awk_cmd1;awk_cmd2}    2.行处理:定址 命令         定址方法: 正则,变量,比较和关系运算        正则需要用//包围起来         ^   行首        $  行尾        .   除了换行符以外的任意单个字符        *   前导字符的零个或多个        .*  所有字符        []  字符组内的任一字符        [^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)        ^[^]    非字符组内的字符开头的行        [a-z] 小写字母        [A-Z] 大写字母        [a-Z] 小写和大写字母        [0-9] 数字        \<  单词头 单词一般以空格或特殊字符做分隔,连续的字符串被当做单词        \>  单词尾        扩展正则 加 -r 参数 或转义         sed -n '/roo\?/p' /etc/passwd           sed -rn '/roo?/p' /etc/passwd        ? 前导字符零个或一个        + 前导字符一个或多个        abc|def abc或def        a(bc|de)f abcf 或 adef        x\{m\}   x出现m次        x\{m,\}  x出现m次至多次(至少m次)        x\{m,n\} x出现m次至n次        NR变量定址                 NR 表示AWK读入的行数            FNR表示读入行所在文件中的行数        # awk '{print NR,FNR,$1}' file1  file2         1 1 aaaaa        2 2 bbbbb        3 3 ccccc        4 1 dddddd        5 2 eeeeee        6 3 ffffff        #            逻辑运算 可直接引用域进行运算            == >= <= != > < ~ !~        # awk 'NR==1 {print}' /etc/passwd        root:x:0:0:root:/root:/bin/bash        #     3.命令 {print $0}    4.读后处理 END {awk_cmd1;awk_cmd2;}

AWK变量
NR 当前记录的个数(全部文件连接后的统计)
FNR 当前记录的个数(仅为当前文件的统计,非全部)
FS 字段分隔符 默认为连续空格或制表符,可以使用多个不同的符号做分隔符 -F[:/]
OFS 输出字符的分隔符 默认是空格
# awk -F: ‘OFS=”=====” {print 1,2}’ /etc/passwd
root=====x
NF 当前读入行的字段个数
ORS 输出记录分隔符 默认是换行
# awk -F: ‘ORS=”=====” {print 1,2}’ /etc/passwd
root x=====bin x=====
FILENAME 当前文件名

引用shell变量的方法
# a=root
# awk -v var=aF:1 == var {print 0}’ /etc/passwd  
    或者 把整个命令拆开传递,让shell变量外露,  
    # awk -F: ‘
1 == "'a’” {print0}’ /etc/passwd
# a=NF
# awk -F: ‘{print a’}’ /etc/passwd

操作符
赋值
= += -= /= *=
逻辑与 逻辑或 逻辑非
&& || !
匹配正则或不匹配,正则需要用 /正则/ 包围住
~ !~
关系 比较字符串时要把字符串用双引号引起来
< <= > >= != ==
字段引用
,而变量引用直接用变量名取
运算符
+ - * / % ++ –
转义序列
\ \自身
$ 转义$
\t 制表符
\b 退格符
\r 回车符
\n 换行符
\c 取消换行

试做
打印uid在30~40范围内的用户名。
打印第5-10行的行号和用户名
打印奇数行
打印偶数行
打印字段数大于5的行
打印UID不等于GID的用户名
打印没有指定shell的用户
打印1..1000以内的7的倍数和包含7的数
统计出每种shell的使用人数,输出格式如下
1
1 /bin/sync
6 /bin/bash
31 /sbin/nologin
1 /sbin/halt
1 /sbin/shutdown
把你主机的所有IP地址提取出来

流程控制
分支结构

if (条件) 动作    若有多个动作,则要用大括号将动作体包含起来  if (条件) {动作1;动作2}# awk -F: '{if ($1 == "root") print $1}' /etc/passwdroot# # awk -F: '{if ($1 == "root") {print $1;print $6}}' /etc/passwdroot/root#if (条件1)    动作1else    动作2# awk -F: '{if ($1 == "root"){print $1}else print $6}' /etc/passwd# awk -F: '{if ($1 == "root") print $1;else print $6}' /etc/passwd上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围if (条件 1)    动作1else if(条件 2)    动作2else if(条件 3)    动作3else    动作4# awk -F: '{if ($1 == "root") print $1;else if ($1 == "seker") print $6;else if ($1 == "zorro") print $7;else print NR}' /etc/passwdroot23...33/home/seker/bin/bash36条件 ? 动作1 : 动作2expr?action1:action2# awk -F: 'var=($3 >= 500)?$1:"system_user" {print $1"\t"$3"\t"var}' /etc/passwd# awk -F: '{print ($3>500?$1:$2)}' /etc/passwd

试做
将系统用户按UID分组标记 0 admin; 1-499 sysuser; 500+ users

输出样式
%s是字符类型,%d数值类型
printf默认是不输出换行的所以要加\n
10和7是偏移量
默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充
注意:格式与输出列之间要有逗号
# awk -F: ‘{printf “%-10s %-10d %s\n”,1,3,$7}’ /etc/passwd

读前处理和读后处理
# awk -F: ‘BEGIN{i=1} {i++} END {print i}’ /etc/passwd
47
#
# awk -F: ‘BEGIN {print NR,NF}’ /etc/passwd
0 0
#
# awk -F: ‘END {print NR,NF}’ /etc/passwd
46 7
#
试做
找出普通用户的用户名并统计数量
# awk -F: ‘BEGIN{i=0} 3 >= 500 {print1;i++} END {print i}’ /etc/passwd
计算UID相加的总和;计算GID相加的总和
计算VSZ和RSS各自的和 并以M单位显示

循环语句  while(条件) {    动作    条件运算  }# awk -F: '{while($3<3) {print $3,$1;$3++}}' /etc/passwd0 root1 root2 root1 bin2 bin2 daemon# BEGIN块可以独立使用,不需要引入文件# awk 'BEGIN{i=1;while(i<100) {print i;i++}}'

试做
打印100以内的偶数
# awk ‘BEGIN{i=1;while(i<100) {if (i%2==0) print i;i++}}’

x=1do {    动作1    x++  } while (x<5)# awk 'BEGIN{i=5;do{print i;i++}while(i<10)}'# awk 'BEGIN{i=5;do{print i;i++}while(i<1)}'for(预置;条件;递增) {    动作  }# awk 'BEGIN {for (x=1;x<=4;x++) print x }'1234## awk 'BEGIN{for (i=1;i<=4;i++) {for (j=1;j<=4;j++) print i,j}}'

试做
使用嵌套的for循环,打印100-999之间的数,个十百位分别用一个for来打印
# awk ‘BEGIN{OFS=”“;for (i=1;i<=9;i++) {for (j=0;j<=9;j++) {for (n=0;n<=9;n++) print i,j,n}}}’
打印乘法口诀表
# cat 99.sh
#!/bin/bash
awk ‘BEGIN{
for(i=1;i<10;i++)
{
for(j=1;j<=i;j++)
printf “%d*%d=%d “,j,i,j*i
print
}

}'# 打印金字塔# cat jin.sh #!/bin/bashawk 'BEGIN{    num=5    for(i=1;i<=num;i++)    {           for (n=1;n<=num-i;n++)            printf "%s"," "        for (j=1;j<=2*i-1;j++)            printf "%s","*"        print    }}'# 逆序输出每个字段达到这样既可/bin/bash/rootroot00xroot# awk -F: '{for (x=NF;x>0;x--) print $x}' /etc/passwd 

继续解决上一个试做题的格式问题
# awk -F: ‘/bash/{for (x=NF;x>0;x--) printf "%-13s",x;printf “\n”}’ /etc/passwd

跳转语句break 跳出循环# awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}'12continue 在达到循环底部之前终止当前循环 从新开始下一次循环# awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}'124next 读入下一行 同时返回脚本顶部 这样可以避免对当前行执行其他操作# awk -F: 'NR > 5 {next} {print $1} END {print NR}' /etc/passwdrootbindaemonadmlp46# exit 使读取动作终止 并将控制移动到END,如果没有END则终止脚本# awk -F: 'NR > 5 {exit} {print $1} END {print NR}' /etc/passwdrootbindaemonadmlp6#

数组
自定义数组
# awk ‘BEGIN {ary[1]=”seker”;ary[2]=”zorro”;print ary[1],ary[2]}’
seker zorro
#
# awk ‘BEGIN {ary[1]=”seker”;ary[2]=”zorro”;for(i in ary) print ary[i]}’
seker
zorro
#
删除一个元素 对元素给空值并不能清除这个元素 要想清除一个元素需要使用delete ary[idx]
# awk ‘BEGIN {ary[1]=”seker”;ary[2]=”zorro”;ary[3]=”blues”;ary[2]=”“;for(i in ary) print ary[i]}’
seker

blues# awk 'BEGIN {ary[1]="seker";ary[2]="zorro";ary[3]="blues";delete ary[2];for(i in ary) print ary[i]}'sekerblues#循环产生数组和取出数组# awk 'BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}'4 1045 1051 1012 1023 103# # awk -F: '{ary[NR]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd1 root2 bin3 daemon4 adm5 lp6 sync7 shutdown8 halt9 mail# awk -F: '{ary[$3]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd10 uucp11 operator12 games13 gopher14 ftp32 rpc37 rpmARGV  命令行中参数数组    # awk '{for (i in ARGV) {print i,ARGV[i]}}'  /etc/passwd /etc/fstab    0 awk    1 /etc/passwd    2 /etc/fstab    #### i 为下标; ARGV[i] 下标为i的值

试做
统计每种shell被使用的次数

函数

算术函数 int
[root@stu254 ~]# awk ‘BEGIN {print int(3.9415)}’
3
[root@stu254 ~]#

随机数函数 rand() srand()
rand() 取值 0 > r < 1 之间 默认的种子是系统时间 精确到秒
srand()取值 0 > r < 1 之间 可以指定种子来影响rand()取值数 默认是系统时间 精确到秒

[root@stu254 ~]# awk ‘BEGIN {srand(222);print int(rand()*100000000)}’
90204196
[root@stu254 ~]#

字符串函数
substr(s,x[,y])
返回字符串s中从位置x起至y的子串,如果没有给出y,则从x开始到结束.
[root@stu254 ~]# awk ‘BEGIN {x=”abcdefxyz”;print substr(x,4,3)}’
def
[root@stu254 ~]#

大写小写
sprintf() 本身并不能打印,做格式转换,将数字转换成ASCII字符

awk ‘BEGIN {for(i=97;i<=122;++i) print tolower(toupper(sprintf(“%c”,i)))}’

字符串长度
length() 如果没有给定字符串则使用$0
[root@stu254 ~]# awk ‘BEGIN {print length(“abcdefxyz”)}’
9

gsub(/abc/,”ABC”,x) 全局字符串替换
从x中用匹配的abc正则替换成ABC
[root@stu254 ~]# awk ‘BEGIN {x=”xyzabcxyzabcxyz”;gsub(/abc/,”ABC”,x);print x}’
xyzABCxyzABCxyz
[root@stu254 ~]# sub 第一次的替换
[root@stu254 ~]# awk ‘BEGIN {x=”xyzabcxyzabcxyz”;sub(/abc/,”ABC”,x);print x}’
xyzABCxyzabcxyz
[root@stu254 ~]#

   gensub(r, s, h [, t])   Search the target string t for matches of the reg-                           ular  expression  r.   If  h is a string beginning                           with g or G, then replace all matches of r with s.                           Otherwise, h is a number indicating which match of                           r to replace.  If t is not supplied,  $0  is  used                           instead.

gensub(正则,替换,范围,目标串)
[root@tch254 ~]# awk ‘BEGIN{print gensub(“zorro”,”AAAA”,”2”,”seker zorro zorro seker”)}’
seker zorro AAAA seker
[root@tch254 ~]# echo seker zorro zorro seker | sed ‘s/zorro/AAAA/2’
seker zorro AAAA seker
[root@tch254 ~]#
[root@tch254 ~]# echo seker zorro zorro seker | awk ‘{0=gensub(“zorro”,”AAAA”,”g”);print}’  
seker AAAA AAAA seker  
[root@tch254 ~]# echo seker zorro zorro seker | awk ‘{
0=gensub(“zorro”,”AAAA”,”2”);print}’
seker zorro AAAA seker
[root@tch254 ~]# echo seker zorro zorro seker | awk ‘{0=gensub(“zorro”,”AAAA”,”h”);print}’  
seker AAAA zorro seker  
[root@tch254 ~]# echo seker zorro zorro seker | awk ‘{
0=gensub(“zorro”,”AAAA”,”1”);print}’
seker AAAA zorro seker
[root@tch254 ~]#

系统函数
getline

交互输入
[root@stu254 ~]# awk -F: ‘BEGIN {printf “Enter Number: “;getline ;for(i=1;i<=$0;i++) print i}’
Enter Number: 3
1
2
3
[root@stu254 ~]#

将输入赋值给变量
[root@stu254 ~]# awk -F: ‘BEGIN {printf “Enter Number: “;getline NUM;for(i=1;i<=NUM;i++) print i}’
Enter Number: 3
1
2
3
[root@stu254 ~]#

从文件中读入
[root@tch254 ~]# awk -F: ‘BEGIN {getline < “/etc/passwd” ; print 3"\t"1}’
0 root
[root@tch254 ~]#

awk -F: ‘BEGIN {while (getline < “/etc/passwd” > 0) print 3"\t"1}’

getline < “/etc/passwd” 从文件中读入,每次读取一行,默认情况下读取的次数等于awk自身引入文件的行数
也可以放到for中来控制读取的次数

0 测试读取的返回值,成功返回1,失败返回-1,0文件末尾

从命令输出中输入
[root@stu254 ~]# awk ‘BEGIN {“uname -a”|getline ;print $3}’
2.6.18-53.el5
[root@stu254 ~]#

system(command)
系统命令要用”“引起来
[root@stu254 ~]# rm -rf abc/
[root@stu254 ~]# awk ‘BEGIN {if(system(“mkdir abc”) != 0 ) print “ERR”}’
[root@stu254 ~]# awk ‘BEGIN {if(system(“mkdir abc”) != 0 ) print “ERR”}’
mkdir: 无法创建目录 “abc”: 文件已存在
ERR
[root@stu254 ~]#
[root@tch254 ~]# awk ‘BEGIN {if(system(“mkdir abc 2>/dev/null”) != 0 ) print “ERR”}’
ERR
[root@tch254 ~]#

awk脚本的介绍 -f 与 #!/bin/awk -f

使用awk添加系统用户
[root@mail ~]# cat useradd.awk

!/bin/awk -f

{
system(“useradd “1";echo"2”|passwd –stdin “$1)
}
[root@mail ~]# cat username
myname 1234
[root@mail ~]#
[root@mail ~]# ./useradd.awk ./username
Changing password for user myname.
passwd: all authentication tokens updated successfully.
[root@mail ~]#

原创粉丝点击