AWK ——是一种用于处理文本的编程语言工具。
英文原义:Aho、Weinberger、Kernighan
中文释义:三位创造者Aho、Weinberger和Kernighan统称
AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法。最初创造 AWK 时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。
awk 之所以成为一种优秀的程序设计语言的原因之一是内置函数的使用,awk定义并支持了一系列的内置函数,由于这些函数的使用,使得awk提供的功能更为完善和强大。
常用语法:
awk [options] ‘commands’ testfiles
options选项
-F 定义字段分隔符,默认分隔符为连续空格或制表符
用$1,$2,$3等顺序表示files中每行以间隔符号分隔的各列不同域
-v 定义变更并赋值,也可以借用次方式从shell变量中引入变量
使用示例:
[root@localhost test]# awk -F”:” ‘{print $1,$7}’ testfile
以冒号作为分隔符,打印第1和第7个字段
[root@localhost test]# awk -F”[:/]” ‘{print $1,$7}’ testfile
以冒号或斜杠 / 作为分隔符,打印第1第7个字段
[root@localhost test]# awk -F”:/” ‘{print $1,$7}’ testfile
以冒号加斜杠 “:/”整体作为分隔符
———————————————————–
command
读前处理 行处理 读后处理
1、读前处理 BEGIN{awk_cmd1;awk_cmd2;}
2、行处理:定址 命令
定址方法:正则,变量,比较,关系运算
正则需要用 / / 包裹起来
常用正则:
^ 行首 $ 行尾
. 除了换行符以外的任意单个字符
* 前导字符的零个或多个
.* 所有字符
[] 字符组内的任一字符
[^] 对字符组内的每个字符取反(不匹配字符组内的每个字符)
^[^] 非字符组内的字符开头的行
[a-z] 小写字母
[A-Z] 大写字母
[a-Z] 小写和大写字母
[0-9] 数字
\< 单词头,以空格或特殊字符做分隔,连续的字符串被当做单词
\> 单词尾
扩展正则
? 前导字符零个或一个
+ 前导字符一个或多个
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 ‘NR==1 {print}’ /etc/passwd
root:x:0:0:root:/root:/bin/bash
命令 如:{print $1,$2}
3、读后处理
END {awk_cmd1;awk_cmd2;}
—————————————————————
AWk的变量
NR AWK处理的总行数
FNR AWK处理的当前文件的行数,非全部
FS 字段分隔符,默认为连续空格或制表符,可以使用多个不同的符号做分隔符,也可在options出使用 -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 当前文件名
更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2013-11/92787p2.htm
相关阅读:
sed与awk常用功能 http://www.linuxidc.com/Linux/2013-06/86099.htm
Linux下shell编程常用grep\awk\sed语法 http://www.linuxidc.com/Linux/2013-07/87047.htm
Linux下Shell编程——awk编程 http://www.linuxidc.com/Linux/2013-06/85527.htm
文本处理工具awk详解 http://www.linuxidc.com/Linux/2013-05/84248.htm
Linux awk命令使用详解 http://www.linuxidc.com/Linux/2012-12/77082.htm
引用shell变量的方法:
(1)使用 -v 引用变量值
[root@localhost test]# a=5
[root@localhost test]# awk -v c=$a -F: ‘NR < c {print NR,$0}’ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
(2)把整个命令拆开传递,让shell变量外露
[root@localhost test]# a=5
[root@localhost test]# awk -F: ‘NR < ‘$a'{print NR,$0}’ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
————————————————————
操作符
赋值 = += -= /= *=
&& ——逻辑与 ||——逻辑或 !——逻辑非
匹配正则或不匹配,正则需要用 /正则/ 包围住
~ !~
关系 比较字符串,要把字符串用双引号引起来
< <= > >= != ==
字段引用
$ 字段引用需要加$ 而变量引用直接用变量名取
运算符
+ – * / % ++ —
转义序列
\\ \自身
\$ 转义$
\t 制表符
\b 退格符
\r 回车符
\n 换行符
\c 取消换行
用法示例:
# awk -F: ‘$3 >= 30 && $3 <= 40 {print $0}’ /etc/passwd
打印出uid在30到40之间的用户信息行
# awk -F: ‘ NR >= 30 && NR <= 40 {print NR,$0}’ /etc/passwd
打印出行号在30到40之间的行
# awk -F: ‘ NR % 2 == 1 {print NR,$1,NF}’ /etc/passwd
打印奇数行
# awk -F: ‘ NR % 2 == 0 {print NR,$1,NF}’ /etc/passwd
打印偶数行
# awk -F: ‘ $3 != $4 {print NR,$1,$3,$4}’ /etc/passwd
打印uid和gid不相等的用户信息行
# awk -F: ‘$7 ~ /bash/ {print NR,$1,$7}’ /etc/passwd
打印第7个字段能匹配 /bash/ 字符串的行
# awk -F: ‘$7 !~ /nologin/ {print NR,$1,$7}’ /etc/passwd
打印第7个字段不能匹配 /nologin/ 字符串的行
————————
数组
自定义数组
# awk ‘BEGIN{ary[1]=”hunan”;ary[2]=”hubei”;print ary[1],ary[2]}’
hunan hubei
# awk ‘BEGIN{ary[1]=”hunan”;ary[2]=”hubei”;for(i in ary) print ary[i]}’
hunan
hubei
环产生数组和取出数组
# awk ‘BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}’
4 104
5 105
1 101
2 102
3 103
# awk -F: ‘{ary[NR]=$1}END{for(i in ary){print i,ary[i]}}’ testfile
4 dbus
5 usbmuxd
6 hsqldb
7 avahi-autoipd
8 rpc
1 root
2 bin
3 myuser
# awk -F: ‘{ary[$3]=$1} END {for(i in ary) print i,ary[i]}’ testfil
流程控制
分支结构
(一) if (条件) 动作
if (条件) {动作1;动作2}
如:
# awk -F: ‘{if ($1 == “root”)print $1}’ /etc/passwd
awk -F: ‘{if ($1 == “root”){print $1;print $7}}’ /etc/passwd
(二) if (条件1)
动作1
else
动作2
如:
# awk -F: ‘{if ($1 == “root”) print $1; else print $6}’ testfile
# awk -F: ‘{if ($1 == “root”) {print $1} else print $6}’ testfile
上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围
(三)if (条件1)
动作1
else if (条件2)
动作2
else if (条件2)
动作3
else
动作4
如:
# awk -F: ‘{if ($1==”root”)print $1;else if($1==”bin”)print $3;else if($1==”myuser”)print $7}’ testfile
(四) 条件 ? 动作1:动作2
expr ? action1:action2
如:
# awk -F: ‘AA=($3>=500?$3:”system_user”){print $1″\t”$3″\t”AA}’ testfile
root 0 system_user
bin 1 system_user
myuser 501 501
———————————————————-
读前处理和读后处理
如:
# awk ‘BEGIN{i=1} {i++} END{print i}’ /etc/passwd
# awk -F: ‘BEGIN{print NR,NF} END{print NR,NF}’ /etc/passwd
0 0
46 7
# awk -F: ‘BEGIN{sum=0} {sum=sum+NF}END{print sum}’ /etc/passwd
322
# awk -F: ‘BEGIN{sum=0} {sum+=NF}END{print sum}’ /etc/passwd
322
BEGIN块可以独立使用,不需要引入文件
# awk ‘BEGIN{i=1;while(i<10) {print i;i++}}’
1
2
3
4
5
6
7
8
9
————————————————————-
循环语句
(一) while (条件)
{
动作
条件运算
}
如:
# awk -F: ‘{while($3<3) {print $3,$1;$3++}}’ /etc/passwd
0 root
1 root
2 root
1 bin
2 bin
2 daemon
(二) do {
动作
条件运算
} while (条件)
如:
# awk ‘BEGIN{i=5;do{print i;i++}while(i<10)}’
5
6
7
8
9
(三)for (预置;条件;递增) {
动作
}
如:
# awk ‘BEGIN{for (i=1;i<5;i++) print i}’
1
2
3
4
(四) 循环for嵌套
如:
# awk ‘BEGIN{for (i=1;i<3;i++) {for (j=1;j<=3;j++) print i,j}}’
1 1
1 2
1 3
2 1
2 2
2 3
# 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}}}’ 使用嵌套的for循环,打印100-999之间的数
# awk -F: ‘{for(x=NF;x>0;x–)print $x}’ testfile 逆序输出
————————————————————
输出样式
# awk -F: ‘{printf “%-10s %-7d %s\n”,$1,$3,$7}’ testfile
root 0 /bin/bash
bin 1 /sbin/nologin
myuser 501 /bin/bash
命令分析:
%s是字符类型,%d数值类型
printf默认是不输出换行的所以要加\n(printf和print不同,print默认每输出一行进行换行)
10和7是偏移量
默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充
注意:格式与输出列之间要有逗号
跳转语句
break 跳出循环
# awk ‘BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}’
1
2
continue 在达到循环底部之前终止当前循环 从新开始下一次循环
# awk ‘BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}’
1
2
4
next 读入下一行 同时返回脚本顶部 这样可以避免对当前行执行其他操作
# awk -F: ‘NR > 5 {next} {print $1} END {print NR}’ /etc/passwd
root
bin
daemon
adm
lp
46
exit 使读取动作终止 并将控制移动到END,如果没有END则终止脚本
# awk -F: ‘NR > 5 {exit} {print $1} END {print NR}’ /etc/passwd
root
bin
daemon
adm
lp
6
——————————————————————–
函数
转换函数,转换成整数
如:
# awk ‘BEGIN{print int(3.934)}’
3
随机数函数 rand() srand()
rand() 取值 0 > r > 1 之间 默认的种子是系统时间 精确到秒
srand()取值 0 > r > 1 之间 可以指定种子来影响rand()取值数 默认是系统时间 精确到秒
echo $RANDOM
如:
# awk ‘BEGIN{print int(rand()*100)}’
23
# awk ‘BEGIN{srand(123);print int(rand()*100)}’
74
# awk -v a=$RANDOM ‘BEGIN{print a}’
22059
字符串函数
substr(s,x,y)
返回字符串s中从位置x起至y的子串,如果没有给出y,则从x开始到结束
如:
# awk ‘BEGIN{aa=”abcdefghi”;print substr(aa,3,4)}’
cdef
# awk ‘BEGIN{aa=”abcdefghi”;print substr(aa,1)}’
abcdefghi
大写小写函数
tolower() 小写函数
toupper() 大写函数
sprintf() 本身并不能打印,做格式转换,将数字转换成ASCII字符
# awk ‘BEGIN{for(i=97;i<=122;++i)print toupper(sprintf(“%c”,i))}’
# awk ‘BEGIN{for(i=97;i<=122;++i)print tolower(sprintf(“%c”,i))}’
字符串长度
length() 如果没有给定字符串则使用$0
# awk ‘BEGIN{print length(“abcdefghi”)}’
9
# awk ‘{print length()}’ /etc/passwd
gsub(/abc/,”ABC”,x)
全局字符串替换,从x中用匹配的abc正则替换成ABC
# awk ‘BEGIN{aa=”abcxyzabcxyzabc”;gsub(/abc/,”ABC”,aa);print aa}’
ABCxyzABCxyzABC
系统交互输入函数——getline
(等同于shell中的read -p “strings” var )
如:
# awk -F: ‘BEGIN{printf “sss: “;getline;for(i=1;i<=$0;i++) print i}’
sss: 4
1
2
3
4
使用getline函数将输入值赋给变量
# awk -F: ‘BEGIN{printf “haoren: “;getline NUM;for(i=1;i<=NUM;i++)print NUM,i}’
haoren: 5
5 1
5 2
5 3
5 4
5 5
从文件中读入
#awk -F: ‘BEGIN {while (getline < “/etc/passwd” > 0) print $3″\t”$1}’
getline < “/etc/passwd” 从文件中读入,每次读取一行,默认情况下读取的次数等于awk自身引入文件的行数
> 0 测试读取的返回值,成功返回1,失败返回-1,0文件末尾
从命令输出中输入
[root@stu254 ~]# awk ‘BEGIN {“uname -a”|getline ;print $3}’
2.6.18-53.el5
system(command)——引入系统命令,系统命令要用””引起来
如:
# awk ‘BEGIN{if(system(“mkdir mulu1”) != 0) print “error”}’
# awk ‘BEGIN{if(system(“mkdir mulu1”) != 0) print “error”}’
mkdir: 无法创建目录”mulu1″: 文件已存在
error
awk脚本—— -f
脚本开头使用 #!/bin/awk -f
如:使用awk脚本添加用户
#!/bin/awk -f
{
system(“useradd “$1”;echo “$2″|passwd –stdin” $1)
}
# cat user.txt
myuser222 123123
myuser333 456456
# ./useradd.awk user.txt
更改用户 myuser222 的密码 。
passwd: 所有的身份验证令牌已经成功更新。
更改用户 myuser333 的密码 。
passwd: 所有的身份验证令牌已经成功更新。