awk命令详解【非常实用】

shell三剑客:grep、sed、awk

cut
-c:字符数来截取 character
-f:字段来截取 field
-d:指定分隔符 默认是tab

awk命令详解
awk其实可以看做一种编程语言。
awk的来源:三个人名:
Alfred Aho,Peter Weinberger,Brian Kernighan

awk工作原理
gawk (gnu awk)

Unix中awk的GNU版本,完成grep和sed的工作 。
支持数学运算,流程该控制内置大量的变量和函数。
awk命令工作原理

与sed一样, 均是一行一行的读取、处理 。
sed作用于一整行的处理, 而awk将一行分成数个字段来处理 。
图解awk命令的简要处理流程:
这里写图片描述

awk的数据字段变量:

$0表示整行文本
$1表示文本中第一个数据字段
$2表示文本中第二个数据字段
$n表示文本中第n个数据字段
awk的用-F来指定分隔符

默认的字段分隔符是任意空白字符(空格或者TAB)
awk命令的完整语法:
awk ‘BEGIN{commands}pattern{commands}END{commands}’ file1

BEGIN是处理数据前执行的命令
END是处理数据后执行的命令
注意:这里的commands指的是awk里面的子命令,并不是shell中的mkdir、ls等命令!!!

例子:

cat passwd|awk -F: ‘BEGIN{print “############”}$3<100{print $1,$3,$6}END{print “@@@@@@@@@@@@@@”}’

执行结果:

############
root 0 /root
dbus 81 /
rpc 32 /var/cache/rpcbind
rpcuser 29 /var/lib/nfs
haldaemon 68 /
postfix 89 /var/spool/postfix
mysql 27 /var/lib/mysql
@@@@@@@@@@@@@@
awk的命令的执行过程:
执行BEGIN{commands}语句块中的语句
从文件或stdin中读取第1行,
有无模式匹配, 若无则执行{}中的语句,
若有则检查该整行与pattern是否匹配, 若匹配, 则执行{}中的语句,
若不匹配则不执行{}中的语句,接着读取下一行
重复这个过程, 直到所有行被读取完毕
执行END{commands}语句块中的语句
awk命令的基本语法:
语法:awk -F 分隔符‘/模式/{动作}’ 输入文件

awk的指令一定要用单引号括起
awk的动作一定要用花括号括起
模式可以是正则表达式、条件表达式或两种组合
如果模式是正则表达式要用/定界符
多个动作之间用;号分开
分隔符在awk里有2种:
输入分隔符 -F指定
输出分隔符 OFS=
例1:只有模式时,相当于grep

cat passwd|awk ‘/liu/’

liu1❌508:508::/home/liu1:/bin/bash
liu2❌509:509::/home/liu2:/bin/bash
例2:只有动作时,就直接执行动作。

who|awk ‘{print $2}’

tty1
pts/0

who

root tty1 2016-06-24 23:20
root pts/0 2016-06-24 23:21 (liupeng.lan)
例3:输出以h开头的行的第一列和第七列。

cat passwd|awk -F: ‘/^h/{print $1,$7}’

haldaemon /sbin/nologin
例4:显示不是以h开头的行的第一列和第七列

awk -F: ‘/[h]/{print $1,$7}’ /etc/passwd
-F指定多个分隔符
例5:以:或者/作为分隔符显示第1列和第10列

awk -F’[😕]’ ‘{print $1,$10}’ /etc/passwd
例6:以【空格:/】作为分隔符–》非常方便!!!
这里写图片描述

awk命令的操作符
正则表达式和bash一致

数学运算:+,-,*,/, %,++,- -
逻辑关系符:&&, ||, !
比较操作符:>,<,>=,!=,<=,== ~ !~
文本数据表达式:== (精确匹配)
~波浪号表示匹配后面的模式
例1:在$2里查找匹配/pts/的,有就输出$1。

who | awk '$2 ~ /pts/{print $1}‘

例2:输出uid为两位的用户名和uid。

cat passwd|awk -F: ‘$3 ~/<…>/{print $1,$3}’

dbus 81
rpc 32
rpcuser 29
haldaemon 68
postfix 89
mysql 27
< 以什么开头。

以什么结尾。
…正则里代表两个字符。
例3:输出1~100能被5整除的或者以1开头的数字。

#seq 100 | awk ‘$1 % 5 == 0 || $1 ~ /^1/{print $1}’
例4:显示uid大于等于500并且家目录在/home下同时shell为bash结尾的用户名,uid,家目录,shell。

cat passwd|awk -F: ‘$3>=500&&$6 ~/^/home/&&$7 ~/bash/{print $1,$3,$6,$7}’

aaa 500 /home/aaa /bin/bash
stua6 501 /home/stua6 /bin/bash
stuv1 502 /home/stuv1 /bin/bash
stuv2 503 /home/stuv2 /bin/bash
练习1:查找出用户名里包含liu的用户,输出用户名和uid及shell。
答:

cat passwd|awk -F’:’ ‘$1 ~/liu/{print $1,$3,$6}’

liu1 508 /home/liu1
liu2 509 /home/liu2
liu3 510 /home/liu3
liu4 511 /home/liu4
liu5 512 /home/liu5
liu 539 /home/liu
练习2:查找出/etc/passwd文件里用户名包含liu并且使用bash的用户。

cat passwd|awk -F’:’ ‘$1 ~/liu/&&$7 ~/bash/{print $1,$7}’

liu1 /bin/bash
liu2 /bin/bash
liu3 /bin/bash
liu4 /bin/bash
liu5 /bin/bash
liu /bin/bash
例题:

awk 'BEGIN{print "line one

line two
line three"}’
line one
line two
line three

awk 'END{print "line one

line two
line three"}'line one
按Ctrl+D才显示最后三行。
line one
line two
line three
①awk里的变量的传递问题?

可以再BEGIN部分定义,整个处理的过程都可以使用。END部分也可以使用。
②shell里的变量传递到awk里的问题?

cat -n passwd

……
这里写图片描述

例:显示文件的行数:

cat -n passwd|awk ‘BEGIN{i=0}{i++}END{print i}’

这里写图片描述

分析:每取一行,i++。最后i的值就正好是passwd文件的行数。

awk命令的内置变量
名称 用途
NF 每行$0的字段数
NR 当前处理的行号
FS 当前的分隔符,默认是空白字符
OFS 当前的输出分隔符,默认是空白字符
NF:number of field,一行里有多少字段。
NR:number of record,当前处理的行号。
FS:field separater,输入分隔符。默认为空白(空格和Tab)。
OFS:out field separater,输出分隔符。
例1:显示每行的字段数目

#awk ‘{print NF}’ /etc/passwd
(默认分隔符是空白,所以字段数大都是1咯)
结果如下图:
这里写图片描述

awk -F: ‘{print NF}’ /etc/passwd

(指定了分隔符了,就是7咯)
结果如下:
这里写图片描述
例2:显示每行的第一字段和最后一个字段

#awk ‘{print 1 , 1, 1,NF}’ /etc/passwd
例3:显示每行的行号和内容

#awk -F: ‘{print NR,$0}’ /etc/passwd
例4:显示第一列和第七列,中间用—隔开

#awk -F: ‘BEGIN{OFS=“—”}{print $1,$7}’ /etc/passwd
简单写法:

#awk -F: ‘OFS=“—”{print $1,$7}’/etc/passwd
这里写图片描述

例5:显示符合模式的用户名和所在的行号最后显示总行号:

#awk ‘BEGIN{FS=“:”}/bash$/{print NR,$1}END{print NR}’ /etc/passwd
例6:显示文件的3到5行(带行号,带内容)

#awk‘NR3,NR5{print NR,$0}’ /etc/passwd
这里写图片描述
显示4或7行(带行号,带内容):

#awk ‘NR4||NR7{print NR,$0}’ /etc/passwd
这里写图片描述

例7:显示文件的前10行(带行号,带内容):

#awk ‘NR<=10{print NR,$0}’ /etc/passwd
这里写图片描述

例8:显示文件的前10行和30到40行:

awk ‘NR<=10||NR>30&&NR<=40{print NR,$0}’ /etc/passwd

这里写图片描述

练习:
1.分析下面三条命令的区别,为什么
①#awk ‘BEGIN{print NR}’ /etc/passwd (执行一次)
这里写图片描述

②#awk ‘{print NR}’ /etc/passwd (执行N次,N为行数)
这里写图片描述
(一直到48(最后一行))

③#awk ‘END{print NR}’ /etc/passwd (执行一次)
这里写图片描述

2.分析下面命令的执行结果
①#awk -F: ‘{print $NR}’/etc/passwd
(解析:第1行去第1个字段,第2行取第2个字段,第n行去第n个字段……)
这里写图片描述

②#awk -F: ‘{print NR, NF, 1,NF, $(NF-1)}’ /etc/passwd
(输出每行的行号,字段数,用户名,最后一个字段,倒数第二个字段)
这里写图片描述

3.只显示df -h结果的第一列文件系统

df -h|awk -F’ ’ ‘{print $1}’

(注意指定分隔符为空白,默认就是空白)
4.显示passwd文件的第5行和第10行的行号和用户名

cat passwd|awk -F: ‘NR5||NR10{print NR,$1}’

练习:
1.使用NF变量显示passwd文件倒数第二列的内容

cat passwd|awk -F: ‘{print $(NF-1)}’

2.显示passwd文件中第5到第10行的用户名

cat passwd|awk -F: ‘NR>=5&&NR<=10{print $1}’

3.显示passwd文件中第7列不是bash的用户名

cat passwd|awk -F: ‘ 7   / [ b a s h ] 7 ~/[^bash] 7 /[bash]/{print $1}’

–》[bash]中括号里的表示取反。
或者:

cat passwd|awk -F: ‘$7 !~/bash/{print $1}’

4.显示passwd文件中行号是5结尾的行号和行

cat passwd|awk -F: ‘NR%10==5{print NR,$0}’

cat passwd|awk -F: ‘NR ~/5$/{print NR,$0}’

5.用ifconfig只显示ip(不能使用tr或者cut命令)

ifconfig|awk -F: ‘/inet addr/{print $2}’|awk ‘{print $1}’

192.168.1.147
127.0.0.1

ifconfig |sed -n ‘/inet addr/p’|awk -F[:" "] ‘{print $13}’

6.使用awk显示eth0的入站流量和出站流量(字节)

ifconfig eth0|awk -F’[: ]’ ‘/RX bytes/{print $13,$19}’

ifconfig eth0|tr -s ’ ‘|awk -F’[: ]’ ‘/RX bytes/{print $4,$9 }’

1025085 370703
7.使用awk命令统计以r开头的用户数目,显示如下效果:
这里写图片描述

cat passwd|awk -F: ‘BEGIN{print “查找结果”;i=0}/^r/{print $1;i++}END{print i}’

查找结果
root
rpc
rpcuser
3
awk命令的引用shell变量
一、awk命令的引用shell变量

-v 引入shell变量
例1:

name=haha

echo|awk -v abc=KaTeX parse error: Expected '}', got 'EOF' at end of input: …me '{print abc,name}’

haha

echo|awk -v abc=$name ‘{print $name}’

echo|awk -v abc=$name ‘{print abc}’

haha --》引用awk变量无需加$
例2:

name=haha;soft=xixi

echo|awk -v abc= n a m e − v e f g = name -v efg= namevefg=soft ‘{print abc,123}’

haha 123
分析:

#!/bin/bash
awk -v var=$1 -F: ‘$1==var{print NR,$0}’ /etc/passwd
[第1个$1是位置变量,是执行此脚本时后面接的参数;第2个$1指的是用户名。]
这里写图片描述

awk命令的函数
awk编程语言内置了很多函数。

length函数
例1:利用length计算字符数目的函数来检查有无空口令用户。

#awk -F: ‘length($2)==0{print $1}’ /etc/passwd /etc/shadow
例2:显示文件中超过50个字符的行。

awk ‘length($0)>50{print NR,$0}’ /etc/passwd

3 rpc❌32:32:Rpcbind Daemon:/var/cache/rpcbind:/sbin/nologin
4 rpcuser❌29:29:RPC Service User:/var/lib/nfs:/sbin/nologin
7 mysql❌27:27:MySQL Server:/var/lib/mysql:/bin/bash
system函数

cat list

xixi 123
haha 456
hehe 789

awk ‘{system("useradd "$1)}’ list

ls /home

haha hehe hello xixi

awk ‘{system("userdel -r "$1)}’ list

【命令用双括号括起,后面有空格】

ls /home

hello
练习:利用system函数给上述用户配置密码。

#awk ‘{system(“useradd $1”);print $1 “is add”}’ list
#awk ‘{system("userdel -r "$1);print $1 “is deleted”}’ list
#awk ‘{system("echo “$2”|passwd --stdin "$1)}’ list
【命令用双括号括起,后面有空格】
awk命令的结构化语句
if语句
1.单分支

#awk -F: ‘{if($1 ~ /<…>/)print $0}’ /etc/passwd
#awk -F: ‘{if($3 >= 500)print $1,$7}’ /etc/passwd
2.双分支

#awk -F: ‘{if($3 != 0) print $1 ; else print $3}’ /etc/passwd
3.多分支

#awk -F: ‘{if($1==“root”) print $1;else if($1==“ftp”) print $2;else if($1==“mail”) print $3;else print NR}’ /etc/passwd
例2:利用awk的if多重分支判断用户的类型,root显示为管理员 。

#awk -F: ‘{if($3==0) print $1,“管理员”;else if($3>0 && $3<500) print $1,“系统用户”;else if($3>=500 && $3 <= 60000) print $1,“普通用户”;else print $1,“其它用户”}’ /etc/passwd
例:利用awk的system命令在/tmp下建立/etc/passwd中与用户名同名的目录 。

#awk -F: ‘{system("mkdir /tmp/ "$1)}’ /etc/passwd
练习1:用1条命令实现将指定目录下大于10K的对象复制到/tmp下(禁止使用find 和for) 。

#cp $(du -a /boot | awk ‘$1>10240{print $2}’) /tmp
练习2:监控多台主机的磁盘分区一旦某台被监控主机的任一分区使用率大于80%, 就给root发邮件报警。

#!/bin/bash
warn=10
ip=(10.10.10.2 10.10.10.3)
for i in “ i p [ @ ] " d o s s h r o o t @ {ip[@]}" do ssh root@ ip[@]"dosshroot@i df -Ph | tr -s " “|awk -v w=10 -F “[ %]” '/^/dev/{if($5>w) print $1,$5”% useage is over 10%”}'>
alert
if [ -s alert ]
then
sed -i “1i KaTeX parse error: Expected 'EOF', got '&' at position 10: i" alert &̲& mail -s "i hd usage” root < alert
fi
done
练习3:检查/var/log/secure日志文件,如果有主机用root用户连接服务器的ssh服务失败次数超过10次(10次必须使用变量),就将这个IP地址加入/etc/hosts.deny文件拒绝其访问,如果这个IP已经存在就无需重复添加到/etc/hosts.deny文件(要求使用awk语句进行字符过滤、大小判断和变量赋值,禁止使用echo、sed、grep、cut、tr命令)

#/bin/bash
awk '/Failed password for root/{print KaTeX parse error: Expected 'EOF', got '}' at position 7: (NF-3)}̲' /var/log/secu…(awk '$1>num {print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' num=NUM test) --》$1就是统计好的次数
for i in I P d o D E N Y = IP do DENY= IPdoDENY=(awk '$2var {print KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' var=i /etc/hosts.deny)
if [[ -z $DENY ]]
then
awk '$2
var {print "sshd: "KaTeX parse error: Expected 'EOF', got '}' at position 2: 2}̲' var=i test >> /etc/hosts.deny
awk '$2var {print “错误次数”$1,"拒绝"KaTeX parse error: Expected 'EOF', got '}' at position 6: 2"访问"}̲' var=i test
else
awk '$2
var {print "已经拒绝"KaTeX parse error: Expected 'EOF', got '}' at position 6: 2"访问"}̲' var=i test
fi
done
awk对行和列的累加
1.awk进行列求和
①统计/etc目录下以.conf结尾的文件的总大小

#find /etc/ -type f -name “*.conf” |xargs ls -l | awk '{sum+=$5} END{print sum}‘
这里写图片描述

②如果要匹配第一列的才累加,需要用到awk的数组和for循环(难点)

cat xferlog | awk ‘{print $7,$8}’ | sort -n >/lianxi/123.txt
awk ‘{a[$1]+=$2}END{for(i in a) print i,a[i]}’/lianxi/123.txt | sort -rn -k2

解析:
a[$1]=a[$1]+KaTeX parse error: Expected 'EOF', got '#' at position 135: …】 ③awk进行行求和 例1:#̲echo 1 2 3 4 5 …i; print sum}’

执行结果:
这里写图片描述

例2:#seq -s ’ ’ 100 | awk ‘{for(i=1;i<=NF;i++) sum+=$i; print sum}’

这里写图片描述

PS:linux里记录行踪的地方

①history -c
②~/.bash_history
③/var/log/secure
④/var/log/lastlog
⑤/var/log/wtmp

awk里面的数组是关联数组怎么理解:
练习:awk里如何使用数组来存放数据?
1.将所有的/etc/passwd所有的用户存放在user数组里。

cat /etc/passwd|awk -F: ‘{user[$1]}’

解析:此时user[root]里面没有值,只是下标或者说索引变成了user[用户名]

cat /etc/passwd|awk -F: ‘{user[$1]=$3}’

解析:此时,将$3的值(也就是uid)赋给user[$1]数组。
这样,就把用户和用户对应的uid关联起来了,用户名做下标关键字,uid做数组元素对应的值。

练习:awk里如何从数组里取出数据?
2.将user数组里的所有值取出来。

cat /etc/passwd|awk -F: ‘{user[$1]=$3}END{for (i in user)print user[i],i}’

这里写图片描述

小结:
awk里关联数组难点的理解:
{a[$1]+=$2}

将$1对应的ip地址作为下标,将$2对应的大小赋值给下标为ip的元素。awk每读取一行就执行一次,重新又将$1对应的ip地址作为下标,执行a[$1]=a[$1]+$2,将上一行的a[$1]的值加上第2行$2值,实现累加的效果。但是ip地址还是那个ip地址,但是值已经累加了。

适用于:某一列不变,而对应的另一列的内容不同的场景。

练习:

username money
feng 100
feng 200
feng 360
li 100
li 150
zhang 90
zhang 88
统计每个人总共花了多少钱。并按总金额降序排序。

#cat money.txt|awk ‘{username[$1]+=$2}END{for(i in username)print i,username[i]}’|sort -nr -k2
这里写图片描述

这里写图片描述

awk里的关联数组之if判断
练习2:/etc/passwd里的所有的用户的uid存放到一个数组,如果用户输入的用户名在数组里,就输出这个用户对应的uid。
用户名做下标;uid做元素值。
答案:

#!/bin/bash
read -p “Please input the username:” u_name
cat /etc/passwd|awk -v U_name=$u_name -F: ‘{user[$1]=$3}END{if (U_name in user)print user[U_name]}’
这里写图片描述

补充:
三种获得uid大于500小于10000的方法:

cat /etc/passwd|awk -F: ‘$3>500&&$3<10000{print $1,$3}’

cat /etc/passwd|awk -F: ‘($3>500&&$3<10000){print $1,$3}’

cat /etc/passwd|awk -F: ‘{if($3>500&&$3<10000)print $1,$3}’

  • 8
    点赞
  • 82
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值