标签:awk命令
awk
调用有二种方式:
1,awk -F"分隔符" ‘{command}‘ filename
分隔符为单个字符,可以省略“”,但是为多个字符时不能省略
2,是将所有的awk命令插入一个单独文件,然后调用
awk -f awk-script-file filename
awk内置变量
$0 | 当前记录行,代表一行记录 |
$1~$n | 当前记录的第n个字段,字段间由FS分隔 |
FS | 输入字段分隔符,默认是空格 |
NF | 当前记录中的字段个数,就是有多少列,一般取最后一列字段 |
NR | 已经读出的记录数,就是行号,从1开始 |
RS | 输入的记录分隔符,默认为换行符 |
OFS | 输出字段分隔符,默是空格 |
字段的引用
$ 字段操作符
$1代表第一列,$2代表第二列。。。n以此类推
$0代表整个输入记录
比较:
sort命令排列文本行,并把文件打印输出到屏幕上。
sort -n -r
-n 按算术值对数字字段排序。数字字段可包含前导空格、可选减号、十进制数字、千分位分隔符和可选基数符。
-r 颠倒指定排序的顺序。
cut -d" " -f1
awk -F" " ‘{print $1}‘
先用awk和cut做截取,来进行几个比较
比较一:用cut和awk截取IP,awk默认以N个空格为分隔符
[root@zhou1 ~]# ifconfig eth0 |grep Bcast |cut -d ":" -f2|cut -d" " -f1
10.0.10.192
[root@zhou1 ~]# ifconfig eth0 |grep Bcast |awk -F: ‘{print $2}‘|awk ‘{print $1}‘
10.0.10.192
[root@zhou1 ~]# ifconfig eth0 |grep Bcast | awk -F" " ‘{print $2}‘|awk -F":" ‘{print $2}‘
10.0.10.192
比较二:awk能以多个字符作为分隔符,cut不能
下面都是以ab为分隔符,截取第二列的做法,cut报错,awk成功
[root@zhou1 ~]# echo "123ab456ab789" |cut -d"ab" -f2
cut: 分界符必须是单个字符
请尝试执行"cut --help"来获取更多信息。
[root@zhou1 ~]# echo "123ab456ab789" |awk -F"ab" ‘{print $2}‘
456
打印所有行 awk ‘{print $0}‘ /etc/passwd
打印第一列 awk -F: ‘{print $1}‘ /etc/passwd
打印第一,三列 awk -F: ‘{print $1"\thaha\t"$3}‘ /etc/passwd
比较三:
[root@li test]# awk -F":" ‘{print $1" 的uid是 "$3}‘ /etc/passwd
--上面这条如果要用cut来实现,得写下面的脚本
#!/bin/bash
#
cat /etc/passwd | cut -d: -f1,3 |while read a
do
head=`echo $a|cut -d: -f1`
tail=`echo $a|cut -d: -f2`
echo "$head的uid是$tail"
done
比较四:
awk -F"[:)]" --以:或)为分隔符
awk -F"[:)]*"--以多个连续的:或多个连续的)为分隔符
# who |tail -1
root pts/0 2013-08-25 10:11 (:0.0)
# who |tail -1 |awk -F":|)" ‘{print $3}‘ --以:或)为分隔符
0.0
[root@zhou1 ~]# echo "1111/:::222///:3333/4444" |awk -F"[/:]*" ‘{print $3}‘ /test/2
3333
--象下面这样的字符串,以点为分隔符可以做,但是点号太多,不好数.所以可以用正则表达式,以连续的多个点来为分隔符
[root@zhou1 ~]# echo "haha,hehe.......................................heihei" |awk -F"[.]*" ‘{print $2}‘heihei
=====================================================================================
awk -F: ‘BEGIN {处理文件前执行的代码块} {处理文件过程中执行的代码块} END {处理文件后执行的代码块}‘ filename
BEGIN {
}
{
}
END {
}
把上面的结构可以与下面的一个基本循环结构做对比
sum=0
for i in `seq 100`
do
sum=$[$sum+$i]
done
echo sum
# cat /etc/fstab |wc -l
10
# awk -F: ‘BEGIN {print "这是第一行"} {print "这是第二行"} {print "这是第三行"} {print "这是第四行"} END {print "这是最后一行"}‘ /etc/fstab |wc -l
32
--这个打印了32行,第一行一次,最后一行一次,中间的三行打了十次;3*10+2=32,正好对应fstab的行数;也就是说中间的代码循环的次数等同于后面的文件的行数
比较下面这两句
1、每一行循环都打印{print "用户名\t\tUID"}{print $1"\t"$3}
[root@zhou1 ~]# awk -F: ‘{print "用户名\t\tUID"}{print $1"\t"$3}‘ /etc/passwd
用户名 UID
root 0
用户名 UID
bin 1
用户名 UID
2、处理文件前执行的代码块{print "用户名\t\tUID"};处理文件过程中执行的代码块{print $1"\t"$3}
[root@zhou1 ~]# awk -F: ‘BEGIN{print "用户名\t\tUID"}{print $1"\t"$3}‘ /etc/passwd
用户名 UID
root 0
bin 1
daemon 2
--下面两种结果相同,都是把列转成行
# head -1 /etc/passwd |awk -F":" ‘{print $1"\n"$2"\n"$3"\n"$4"\n"$5"\n"$6"\n"$7}‘
# head -1 /etc/passwd |awk -F":" ‘{print $1} {print $2} {print $3} {print $4} {print $5} {print $6}{print $7}‘
把/etc/passwd的第一行,按照:分为7列,左右倒序排列
# head -1 /etc/passwd |cut -d":" -f7,6,5,4,3,2,1
root:x:0:0:root:/root:/bin/bash
--用cut,列数反着写,还是没有倒序,所以应该写一个循环,然后使用echo -n去再排列出来
换成awk来做
[root@zhou1 ~]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@zhou1 ~]# head -1 /etc/passwd |awk -F: ‘{print $7":"$6":"$5":"$4":"$3":"$2":"$1}‘
/bin/bash:/root:root:0:0:x:root
[root@zhou1 ~]# head -1 /etc/passwd |awk -F: ‘BEGIN {OFS=":"}{print $7,$6,$5,$4,$3,$2,$1}‘
/bin/bash:/root:root:0:0:x:root
--OFS是一个内置的变量,表示定义输出的分隔符
--上面这可能会有一个问题,就是上面做的只有7列,如果我有700列,我不可能手动从$700写到$1吧;所以可以用awk的for循环来做.(后面有一个例子会讲到)
awk可以用做小数(浮点数)的运算
[root@zhou1 ~]# echo | awk ‘{print 2.13*2}‘
4.26
=======================================================================================
--awk 内置变量
FS 设置分隔符,等同于-F
NF 代表字段数因为NF是列数,所以$NF就是代表最后一个列
NR 代表当前处理第几行
awk关系操作符
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
awk逻辑操作符
&&逻辑与
| |逻辑或
!非
awk运算操作符
+ - * / %
^ 幂 比如:2的三次方 2^3 --shell里面求幂为2**3
练习:用netstat -ntl 截取所有开放监听的端口号
[root@zhou1 ~]# netstat -ntl |grep -Ev "Active|Proto" |awk -F" " ‘{print $4}‘ |awk -F"[:]*" ‘{print $2}‘
111
22
631
25
56579
111
22
1
1
56511
[root@zhou1 ~]# netstat -ntl |grep -Ev "Active|Proto" |awk ‘{print $4}‘ |awk -F: ‘{print $NF}‘
111
22
631
25
56579
111
22
631
25
56511
截取/etc/passwd前五行的倒数第二列
[root@zhou1 ~]# head -5 /etc/passwd |awk -F":" ‘{print $(NF-1)}‘
/root
/bin
/sbin
/var/adm
/var/spool/lpd
练习:
cat 1.txt
1 2 3
1 2 3
cat 2.txt
a b c
a b c
要求得到结果
2 a c
2 a c
[root@zhou1 ~]# paste /test/1.txt /test/2.txt |awk -F " " ‘{print $2"\t"$4"\t"$6}‘
2 a c
2 a c
[root@zhou1 ~]# paste /test/1.txt /test/2.txt |awk -F " " ‘BEGIN{OFS="\t"}{print $2,$4,$6}‘
2 a c
2 a c
打印第五行
[root@zhou1 ~]# head -5 /etc/passwd |tail -1
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@zhou1 ~]# awk ‘NR==5 {print $0}‘ /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
[root@zhou1 ~]# awk ‘{if(NR==5) print $0}‘ /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
打印第五行的第五列
[root@zhou1 ~]# head -5 /etc/passwd |tail -1 |cut -d":" -f5
lp
[root@zhou1 ~]# awk -F":" ‘NR==5 {print $5}‘ /etc/passwd
lp
[root@zhou1 ~]# awk -F":" ‘{if(NR==5) print $5}‘ /etc/passwd
lp
打印每一行的最后一列
[root@zhou1 ~]# awk -F":" ‘{print $NF}‘ /etc/passwd
/bin/bash
/sbin/nologin
找出/etc/以.conf结尾的文件的名字(如:kernelcap-2.6.18-164.el5.conf,只需要得到kernelcap-2.6.18-164.el5就可以了)
[root@zhou1 ~]# find /etc/ -name "*.conf" |awk -F/ ‘{print $NF}‘ |awk -F".conf" ‘{print $1}‘
打印每行的字段数
[root@zhou1 ~]# awk -F: ‘{print NF}‘ /etc/passwd
打印第五行的字段数
[root@zhou1 ~]# awk -F: ‘NR==5{print NF}‘ /etc/passwd
7
打印最后一行的最后一列
# awk -F: ‘END {print $NF}‘ /etc/passwd
打印前五行
# awk ‘NR<6 {print $0}‘ /etc/passwd
打印五到十行,并在前面加上行号
# cat -n /etc/passwd | awk ‘NR>=5 && NR<11 {print $0}‘
# awk ‘NR>=5 && NR<11 {print NR,$0}‘ /etc/passwd
打印奇数行 (删除偶数行)
# awk ‘NR%2==1 {print NR,$0}‘ /etc/passwd
打印偶数行 (删除奇数行)
# awk ‘NR%2==0 {print NR,$0}‘ /etc/passwd
对/etc/passwd里的用户做分类,分成管理员,系统用户,普通用户(只显示用户名,用awk)
awk -F: ‘$3==0 {print $1}‘ /etc/passwd
awk -F: ‘$3>0 && $3<500 || $3==65534 {print $1}‘ /etc/passwd
awk -F: ‘$3>=500 && $3!=65534 {print $1}‘ /etc/passwd
找出每天18:30以后下班的打卡记录
120 张三 2013-7-31 18:19:28
120 张三 2013-7-30 18:58:45
120 张三 2013-7-30 22:41:47
120 张三 2013-7-29 22:15:23
[root@zhou1 ~]# cat /test/2 |awk -F"[: ]" ‘$4>18 || $4==18 && $5>=30 {print $0}‘
[root@zhou1 ~]# cat /test/2 |awk -F" " ‘$4>="18:30:00" {print $0}‘
假设9点整上班,算出下面这几天这几个人分别迟到多少次
张三 2013-8-25 9:19:28
李四 2013-8-25 8:58:45
王五 2013-8-25 8:41:47
马六 2013-8-25 9:12:52
田七 2013-8-25 9:01:47
张三 2013-8-24 8:49:28
李四 2013-8-24 8:54:45
王五 2013-8-24 9:11:47
马六 2013-8-24 9:02:52
田七 2013-8-24 9:04:47
张三 2013-8-23 9:29:28
李四 2013-8-23 8:57:45
王五 2013-8-23 8:41:47
马六 2013-8-23 9:08:52
田七 2013-8-23 9:09:47
张三 2013-8-22 9:24:28
李四 2013-8-22 9:16:45
王五 2013-8-22 9:11:47
马六 2013-8-22 8:52:52
田七 2013-8-22 8:44:47
[root@zhou1 ~]# cat /test/2 |awk -F" " ‘$3>="9:00:00"{print $1}‘ |sort |uniq -c |sort -n |awk -F" " ‘BEGIN{print "迟到人姓名\t迟到次数"}{print $2"\t\t"$1}‘
sort排序,uniq -c 统计
打印所有的列数的总和
--提示:awk是由上往下一行一行的扫描,类似写shell脚本时的循环语句,在这里是自动循环
--思路:先定义一个变量值为0,每扫一行,就加上那一行的列数(NF),最后打印出结果
[root@zhou1 ~]# awk -F: ‘BEGIN {sum=0} {sum=sum+NF} END {print sum}‘ /etc/passwd
308
打印列数大于5的总行数
# awk -F: ‘BEGIN {sum=0} NF>5 {sum=sum+1} END {print sum} ‘ /etc/passwd
# awk -F: ‘BEGIN {sum=0} { if (NF>5) sum=sum+1} END {print sum} ‘ /etc/passwd
# awk -F: ‘BEGIN {sum=0} {NF>5 && sum=sum+1} END {print sum} ‘ /etc/passwd
打印列数大于5的总行数和总列数
# awk -F: ‘BEGIN {line=0;field=0} NF>5 { line=line+1;field=field+NF} END {print "大于5的总行数为"line"\n大于5的总列数为"field}‘ /etc/passwd--正确的写法
# awk -F: ‘BEGIN {line=0;field=0}{ NF>5 && line=line+1;field=field+NF} END {print "大于5的总行数为"line"\n大于5的总列数为"field}‘ /etc/passwd--错误的写法,因为这里NF>5的条件只影响到了line没有影响到field
# awk -F: ‘BEGIN {line=0;field=0} { if (NF>5) line=line+1; field=field+NF} END {print "大于5的总行数为"line"\n大于5的总列数为"field}‘ /etc/passwd--错误的写法,因为这里NF>5的条件只影响到了line没有影响到field
# awk -F: ‘BEGIN {line=0;field=0}{ NF>5 && line=line+1;NF>5 &&field=field+NF} END {print "大于5的总行数为"line"\n大于5的总列数为"field}‘ /etc/passwd--正确写法
# awk -F: ‘BEGIN {line=0;field=0} { if (NF>5) line=line+1; if (NF>5) field=field+NF} END {print "大于5的总行数为"line"\n大于5的总列数为"field}‘ /etc/passwd--正确写法
打印列数大于5小于8,并且行数为奇数行的总行数和总列数
[root@zhou1 ~]# awk -F: ‘BEGIN{hang=0;lie=0} NF>5 && NF<8 && NR%2==1{hang=hang+1;lie=lie+NF} END{print "行数:"hang"\n列数:"lie}‘ /etc/passwd
统计/etc/passwd一共出现了多少个bash字符(要求使用awk)
# grep -o bash /etc/passwd |wc -l
# awk -F"bash" ‘BEGIN {sum=0} { sum=sum+NF-1 } END {print sum}‘ /etc/passwd
=====================================================================================
--awk外部脚本
脚本的结构
BEGIN {
}
{
}
END {
}
例 :把 awk -F: ‘{print $1}‘ /etc/passwd 改成写外部脚本的形式
#!/bin/bash
#
BEGIN{
FS=":" --FS 输入字段分隔符,默认是空格}
{
print $1
}
[root@zhou1 ~]# awk -f /test/3 /etc/passwd
awk -F: ‘BEGIN {sum=0} {if (NF>5) {sum=sum+1}} END {print sum}‘ /etc/passwd
BEGIN {
FS=":" --FS 输入字段分隔符,默认是空格
sum=0
}
{
if (NF>5) --或者把这两行写成 NF>5 && sum=sum+1
sum=sum+1
}
END {
print sum
}
打印列数大于5小于8,并且行数为奇数行的总行数和总列数(用awk脚本写)
[root@zhou1 ~]# awk -F: ‘BEGIN{hang=0;lie=0} NF>5 && NF<8 && NR%2==1{hang=hang+1;lie=lie+NF} END{print "行数:"hang"\n列数:"lie}‘ /etc/passwd
BEGIN{
FS=":"
line=0
field=0
}
{
if (NF>5 && NF<8 && NR%2==1 )
{line=line+1; field=field+NF}
}
END{
print line"\n"field
}
===================================================================================
利用printf格式化输出
[root@li shell04]# awk ‘BEGIN {print "hello world"}‘
hello world
[root@li shell04]# awk ‘BEGIN {printf "hello world"}‘
hello world[root@li shell04]#
--从上面看到print和printf直接使用的主要区别就是printf不自动换行,需要使用\n来换行
格式:
printf {format_expression[,argument]}
两个主要的格式说明符是s和d,s代表字符串,d表示十进制整数
[root@zhou1 ~]# ls -l |grep -v 统计 |awk ‘{ printf ("%d%s\n",$5,$NF)}‘
0128
2216anaconda-ks.cfg
72233install.log
13985install.log.syslog
4096公共的
4096模板
4096视频
4096图片
4096文档
4096下载
4096音乐
4096桌面
例:倒序排序所有字段(/etc/passwd) --因为/etc/passwd只有7列,所以可以直接写出来,但如果列数太多,就要用到下面的循环写法了
cat /etc/passwd |awk -F: ‘{print $7":"$6":"$5":"$4":"$3":"$2":"$1}‘
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 -F: ‘$3==65534 {print $1}‘ /etc/passwd
--这是通过uid的值,找用户名,条件用到了数值的匹配
nfsnobody(域名用户)
# awk -F: ‘$1=="nfsnobody" {print $3}‘ /etc/passwd--这反过来,匹配字符串,来查找其它内容;这里就要用到现在讲的字符匹配
65534
完全匹配
# awk -F: ‘$1=="oo" {print $0}‘ /etc/passwd
部分匹配
# awk -F: ‘$1~"oo" {print $0}‘ /etc/passwd
# awk -F: ‘$1~/oo/ {print $0}‘ /etc/passwd
不匹配
# awk -F: ‘$1!="oo" {print $0}‘ /etc/passwd
# awk -F: ‘$1!~"oo" {print $0}‘ /etc/passwd
找a用户的uid
# cat /etc/passwd |grep ^a: |cut -d":" -f3
# awk -F: ‘$1=="a" {print $3}‘ /etc/passwd
查找用户名里有a字母的用户个数
# grep ^.*a.*: /etc/passwd |wc -l--错误写法(因为它无法定义:符号是第几个)
# grep .*a.*:.*:.*:.*:.*:.*:.* /etc/passwd | wc -l --正确
# grep ^[^:]*a[^:]*: /etc/passwd |wc -l --正确
# awk -F: ‘$1~"a" {print $1}‘ /etc/passwd |wc -l
# awk -F: ‘BEGIN {sum=0} $1~"a" {sum=sum+1} END {print sum}‘ /etc/passwd
例:统计/etc/passwd里以/sbin/nologin结束的用户名,把用户名打印出来,并统计个数
--不用awk的写法,两句命令
# cat /etc/passwd |grep /sbin/nologin$ |cut -d":" -f1
# cat /etc/passwd |grep /sbin/nologin$ |cut -d":" -f1 |wc -l
# awk -F: ‘BEGIN {sum=0} $NF=="/sbin/nologin" {printf ("%s ",$1) ;sum=sum+1} END {print "\n一共有:"sum"个"}‘ /etc/passwd
========================================================================================
--awk的字符串函数
长度函数 length()
打印出/etc/passwd的所有用户名,并统计其字符长度
awk -F: ‘{print $1,length($1)}‘ /etc/passwd
[root@li shell04]# head -1 /etc/passwd |awk -F: ‘{print length($0)}‘
31
[root@li shell04]# head -1 /etc/passwd | wc -L
31
例:查找出用户名长度大于5的用户,显示用户名
# awk -F: ‘length($1)>5 {print $1}‘ /etc/passwd
例: 查找/etc/passwd文件里一共有多少个字符
awk ‘BEGIN {sum=0} {sum=sum+length($0)} END {print sum}‘ /etc/passwd
wc -m /etc/passwd --这种算法会把每行的换行符也算一个字符加上去,所以这条命令的结果会比上面awk算的结果要正好大于文件的行数
index 位置函数
找出oo字符串在/etc/passwd的所有用户名内的第几位
# awk -F: ‘{print index($1,"oo")}‘ /etc/passwd
大小转换
toupper
tolower
# awk -F: ‘{print tolower(toupper($1))}‘ /etc/passwd
substr 截取函数
# awk -F: ‘{print substr($1,1,2)}‘ /etc/passwd
--把$1从第一个字符开始,截取2个(而不是从第一个到第二个)
# echo 12345356346343234sfsahaha34523 |awk ‘{print substr($0,index($0,"haha"),4)}‘
haha
例:截取下面这条命令结果里的4-7个字符
# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
方法一:
# head -1 /etc/passwd |cut -c4-7
方法二: --大写F后和两个连着的引号中间要有一个空格才行
# head -1 /etc/passwd |awk -F "" ‘{print $4$5$6$7}‘
方法三:
# head -1 /etc/passwd |awk ‘BEGIN{FS=""} {print $4$5$6$7}‘
方法四:
# head -1 /etc/passwd | awk -F: ‘{print substr($0,4,4)}‘
方法五:
a=`head -1 /etc/passwd`
echo ${a:3:4}
方法六:
head -1 /etc/passwd |sed -r ‘s/(...)(....)(.*)/\2/g‘
例:查找当前目录下子目录(不包含子目录下的子目录)的目录名
方法一:
# find /etc/ -type d -maxdepth 1
方法二:
# ll /etc/ | awk ‘substr($0,1,1)=="d" {print $NF}‘
方法三:
for i in /etc/*
do
[ -d $i ] && echo $i
done
方法四:
# ll /etc/ |grep ^d | awk ‘{print $NF}‘
替换函数
sub 单替换
gsub 全替换
[root@li shell04]# awk -F: ‘NR==1 {sub(/o/,"O",$0);print $0}‘ /etc/passwd
rOot:x:0:0:root:/root:/bin/bash
[root@li shell04]# awk -F: ‘NR==1 {sub(/o/,"O");print $0}‘ /etc/passwd
rOot:x:0:0:root:/root:/bin/bash
[root@li shell04]# awk -F: ‘NR==1 {gsub(/o/,"O",$0);print $0}‘ /etc/passwd
rOOt:x:0:0:rOOt:/rOOt:/bin/bash
[root@dns shell04]# awk -F: ‘NR==1 {gsub(/\/bin\/bash/,"/sbin/nologin",$0);print $0}‘ /etc/passwd
root:x:0:0:root:/root:/sbin/nologin
[root@zhou1 ~]# awk -F: ‘NR==1 {gsub("/bin/bash","/sbin/nologin");print $0}‘ /etc/passwd
root:x:0:0:root:/root:/sbin/nologin
标签:awk命令
原文地址:http://8179624.blog.51cto.com/8169624/1637220