awk的精妙讲解

时间:2022-03-11 16:05:16

  调用:
1.调用awk:

第一种方式:命令行方式
awk [-F field-separator] 'commands' input-file(s)
[-F域分隔符]是可选的,因为awk使用空格作为缺省的域分隔符,因此如果要浏览域间有空格的文本,不必指定这个选项,如果要浏览诸如passwd文件,此文件各域以冒号作为分隔符,则必须指明-F选项,如:
awk -F: 'commands' input-file

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

第三种方式是将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-scrīpt-file input-files(s)
-f选项指明在文件awk_scrīpt_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名。 

模式和动作

任何awk语句都由模式和动作组成。在一个awk脚本中可能有许多语句。模式部分决定动作语句何时触发及触发事件。处理即对数据进行的操作。如果省略模式 部分,动作将时刻保持执行状态。模式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段 BEGIN和END。使用BEGIN语句设置计数和打印头。BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文本开始执行。END语 句用来在awk完成文本浏览动作后打印输出文本总数和结尾状态标志。

域和记录
使用$1,$3表示参照第1和第3域,注意这里用逗号做域分隔。如果希望打印一个有5个域的记录的所有域,可使用$0,意即所有域。
为打印一个域或所有域,使用print命令。这是一个awk动作

模式和动作
模式:两个特殊断 BEGIN和END
动作:实际动作大多在{}内指明

输出
1.抽取域
awk -F: '{print $1}' /etc/passwd

2.保存输出
awk -F: '{print $1}' /etc/passwd | tee user 使用tee命令,在输出文件的同时,输出到屏幕

使用标准输出
awk -F: '{print $1}' /etc/passwd >user3

4.打印所有记录
awk -F: '{print $0}' /etc/passwd

5.打印单独记录
awk -F: '{print $1,$4}' /etc/passwd

6.打印报告头
awk -F: 'BEGIN {print "NAME\n"} {print $1}' /etc/passwd

7.打印结尾
awk -F: '{print $1} END {print "this is all users"}' /etc/passwd
awk -F: '{print $1} END {print "this is all users\n"}' /etc/passwd 

awk -F: '{print $1} END {print "\nthis is all users"}' /etc/passwd 

条件操作符
1.匹配
awk -F: '{if($1~/root/) print }' /etc/passwd //{if($1~/root/) print}表示如果field1包含root,打印它

awk -F: '{if($1$2~/x/) print }' /etc/passwd //{if($1~/root/) print}表示如果field的第一和第二个域包含x,打印它

2.精确匹配
使用等号 ==
awk -F: '{if($3=="0") print }' /etc/passwd 
上述的"0"的引号不能去掉


3.不匹配
!~
awk -F: '{if($1!~/linuxtone/) print }' /etc/passwd

!=
精确不匹配
awk -F: '{if($1!="linuxtone") print }' /etc/passwd

4.小于
<
5.小于等于
<=
6.大于
>
.........
7.设置大小写
awk '/[Rr]oot/' /etc/passwd
匹配任意大小的R或者r,符合就输出


8.任意字符
awk -F: '{if($1~/^...t/) print}' /etc/passwd //^...t表示第四个字幕是t

9.或关系匹配
awk -F: '{if ($1~/(squid|nagios)/) print}' /etc/passwd

10.行首
awk '/^root/' /etc/passwd // ^root(行首包含root)

11.AND &&
awk -F: '{if($1=="root" && $3=="0") print}' /etc/passwd

12.OR ||

内置变量:
ARCC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FNR 浏览文件的记录数
FS 置顶分隔符,等价于-F
NF 浏览记录的域的个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符

打印有多少行记录
awk 'END {print NR}' /etc/passwd

设置输入域到变量名
awk -F: '{name=$1; path=$7; if(name~/root/) print name "\tpath is:" path}' /etc/passwd

域值比较操作
awk '{if($6<$7) print $0}' input-file

修改文本域只显示修改改记录
awk -F: '{if($1=="nagios") {$1="nagios server" ; print }}' /etc/passwd

文件长度相加
ls -l|awk '/^[^d]/ {print $9"\t" $5} {tot+=$5} END {print "total kb:"tot}'

内置的字符窜函数
gsub(r,s) 在整个$0中用s替代r
gsub(r,s,t) 在整个t中用s替代r
index(s,t) 返回s中字符串t的第一位置
length(s) 返回s长度
match(s,r) 测试s中是否包含匹配r的字符串
split(s,a,fs) 在fs上将s分成序列a
sub(s, ) 用$0中最左边也是最长的字符串替代
subtr(s,p) 返回字符串s中从p开始的后缀部分
substr(s,p,n) 返回字符串s中从p开始长度为n的后缀部分

1.gsub
awk 'gsub(/^root/,"netseek") {print}' /etc/passwd 将与root开头的root替换为netseek

awk 'gsub(/0/,2) {print}' /etc/fstab 

awk '{print gsub(/0/,2) $0}' /etc/fstab 

2.index
awk 'BEGIN {print index("root","o")}' 查询字符串root中o出现的第一位置

awk -F: '$1=="root" {print index($1,"o")" "$1}' /etc/passwd

awk -F: '{print index($1,"o") $1}' /etc/passwd

3.length
awk -F: '{print length($1)'} /etc/passwd

awk -F: '$1=="root" {print length($1)}' /etc/passwd

4.match (在ANCD中查找C的位置)
awk 'BEGIN {print match("ANCD",/C/)}'

5.split
返回字符串数组元素个数
awk 'BEGIN {print split("123#456#789", myarray, "#")}'

6.sub 只能替换指定域的第一个0
awk 'sub(/0/,2) {print }' /etc/fstab

7.substr 
按照起始位置及长度返回字符串的一部分
awk 'BEGIN {print substr("www.linuxtone.org",5,9)}' //第5个字符开始,取9个字符。

awk 'BEGIN {print substr("www.linuxtone.org",5)}' //第5个位置开始,取后面的所有.

字符串屏蔽序列
\b 退格键
\f 走纸换页
\n 新行
\r 回车
\t tab
\c 任意其他特殊字符
\ddd 八进制

很简单的例子
awk -F: '{print $1,"\b"$2,"\t"$3}' /etc/passwd 输出函数printf(注意是printf不是print,两者效果不同的)
printf函数拥有几种不同的格式化输出功能

printf修饰符
- 左对齐
Width 域的步长0表示0步长
.prec 最大字符串长度,或小数点右边的位数


awk printf格式
%c ASCII字符
%d 整数
%e 浮点数,科学计数法
%f 浮点数
%g awk决定使用哪种浮点数转换,e或者f
%o 八进制数
%s 字符串
%x 十六进制数

1.字符串转换
echo "65" | awk '{printf"%c\n",$0}'

awk 'BEGIN {printf "%c\n",65}'

awk 'BEGIN {printf "%f\n",999}'

2.格式化输出
awk -F: '{printf "%-15s %s\n",$1,$3}' /etc/passwd

awk -F: 'BEGIN {printf"USER\t\tUID\n"} {printf "%-15s %s\n",$1,$3}' /etc/passwd

3.向一行awk命令传值
who | awk '{if ($1 == user) print $1 " you are connected to:" $2}' user=$LOGNAME

4.awk脚本文件 (在文件名字后面加后缀.awk方便区分)
#!/bin/awk -f
BEGIN{
FS=":"
print "User\t\tUID"
print"____________________________"
}

{printf "%-15s %s\n",$1,$3}

END{
print "END"

}

转载自http://mcshell.blog.51cto.com/803455/211440,阅读之后,情不自禁的转载了