gawk - pattern scanning and processing
language
awk
调用有三种方式:
1,awk -F"分隔符" "command" filename
2,将所有命令插入一个文件,使它权限程序可执行,然后当成脚本调用它
3,是将所有的awk命令插入一个单独文件,然后调用
awk -f awk-script-file filename
字段的引用
$ 字段操作符
$1代表第一列,$2代表第二列。。。n以此类推
$0代表整个输入记录
比较:
cut -d" " -f1
sort -t" " -k1
awk -F" " '{print $1}'
比较用cut和awk截取IP
ifconfig eth0 |grep Bcast |cut -d ":" -f2|cut -d" " -f1
ifconfig eth0 |grep Bcast |awk -F: '{print $2}'|awk '{print $1}'
ifconfig eth0 |grep Bcast | awk -F" " '{print $2}'|awk -F":" '{print $2}'
--awk默认以N个空格为分隔符
打印所有行 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
[root@dns ~]# awk -F":" '{print $1"的uid是"$3",登录shell 是 "$7}' /etc/passwd
$n n不一定要用整数,也可以用变量值代替
echo a b c |awk 'BEGIN {one=1;two=2} {print $(one+two)}'
awk -F: ‘BEGIN {处理文件前执行的代码块} {处理文件过程中执行的代码块} END {处理文件后执行的代码块}' filename
BEGIN {
}
{
}
END {
}
[root@dns ~]# awk -F: 'BEGIN {print "这是第一行"} {print $0} END {print "这是最后一行"}' /etc/passwd
这是第一行
用awk打印表格
结构如下:
# echo | awk '{print "第一行"} { print "第二行"} { print "第三行"} {print "第四行"}'
第一行
第二行
第三行
第四行
[root@li ~]# head -1 /etc/passwd |awk -F: 'BEGIN {print "*************"} {print "* "$1" *"}{print "* "$2" *"}{print "* "$3" *"}{print "* "$4" *"}{print "* "$5" *"}{print "* "$6" *"}{print "* "$7" *"} END {print "*************"}'
*************
* root *
* x *
* 0 *
* 0 *
* root *
* /root *
* /bin/bash *
*************
--结果的对齐方面可以自己再去调整
===================================
--awk 内置变量
FS 设置分隔符,等同于-F
NF 代表字段数
$NF 代表最后一个字段数
NR 代表当前处理第几行
练习:用netstat -ntl 截取所有开放的端口号
netstat -ntl |grep -v Active| grep -v Proto|awk '{print $4}'|awk -F: '{print $NF}'
netstat -ntlup |grep -Ev "Active|Proto" |awk '{print $4}' |awk -F: '{print $NF}'
grep增强模式
查找/etc/passwd里包含root或daemon的行
cat /etc/passwd |grep -E "(root|daemon)"
查找/etc/passwd里包含root或daemon或adm的行
cat /etc/passwd |egrep "(root|adm|daemon)"
回顾上次的一个题目,把/etc下所有的.conf结尾的文件拷到一个目录,再改为.html结尾;不用rename,用awk来截
[root@li ~]# find /etc/ -name "*.conf" |awk -F/ '{print $NF}' |awk -F".conf" '{print $1}
打印第五行
head -5 /etc/passwd |tail -1
awk 'NR==5 {print $0}' /etc/passwd
打印第五行的第五列
head -5 /etc/passwd |tail -1 |cut -d":" -f5
awk -F":" 'NR==5 {print $5}' /etc/passwd
打印每一行的最后一列 awk -F: '{print $NF}' /etc/passwd
或者awk '{FS=":"} {print $NF}' /etc/passwd --第一行会打印出整行
打印第五行awk 'NR==5 {print $0}' /etc/passwd
或者 awk '{if (NR==5) print $0}' /etc/passwd
打印每行的字段数 awk -F: '{print NF}' /etc/passwd
打印第五行的字段数 awk -F: 'NR==5 {print NF}' /etc/passwd
打印最后一行awk -F: ' END {print $0} ' /etc/passwd
打印最后一行的最后一列 awk -F: ' END {print $NF} ' /etc/passwd
或者:awk -F: '{a=$NF}END {print a} ' /etc/passwd
awk关系操作符
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
awk逻辑操作符
&& 逻辑与
| | 逻辑或
! 非
awk运算操作符
+ - * / %
^ 幂 比如:2的三次方 2^3 --/bin/bash里面求幂为2**3
打印前五行
awk -F: 'NR<=5 {print $0}' /etc/passwd
打印五到十行,并在前面加上行号
# awk -F: 'NR>=5 && NR<=10 {print NR,$0}' /etc/passwd
打印奇数行 (删除偶数行)
awk -F: 'NR%2==1 {print NR,$0}' /etc/passwd
打印偶数行 (删除奇数行)
awk -F: 'NR%2==0 {print NR,$0}' /etc/passwd
删除五分之一的行(打印其五分之四的行,要求这五分之一的行号间隔平均)
awk -F: 'NR%5!=1 {print NR,$0}' /etc/passwd
打印/etc/passwd里普通用户的行
awk -F: '$3>=500 && $3!=65534 {print $0}' /etc/passwd
打印字段数大于6的行
awk -F: 'NF>6 {print $0}' /etc/passwd
打印所有的列数的总和
--提示:awk是由上往下一行一行的扫描,类似写shell脚本时的循环语句,在这里是自动循环
--思路:先定义一个变量值为0,每扫一行,就加上那一行的列数(NF),最后打印出结果
# awk -F: 'BEGIN {a=0} {a=a+NF} END {print a}' /etc/passwd
打印列数大于5的总行数
awk -F: 'BEGIN {a=0} { if (NF>5) a=a+1} END {print a}' /etc/passwd
综合运算 echo |awk '{print 10^2+(90-80)}'
也可以进行浮点数运算 echo |awk '{print 10.9^2+(90.5-80.2)/3}'
例1:监控磁盘使用率,高于80%的找出来,输出警告,发送邮件给管理员
df -h |grep -v 容量|awk '{print $1,$5}'|awk -F% '{print $1}' |while read a
do
used=`echo $a| awk '$2>80 {print $1" is used:" $2"% warning!!!!!!!"}'`
echo $used >> /tmp/used.txt
done
mail root < /tmp/used.txt
df -l |grep -v Filesystem |awk '{ if ($3*100/$2>80) print $1"使用率超过80%"}' | mail root
例2:计算swap总量,使用量,剩余量,使用百分比,剩余百分比
格式要求为:
total used free used% free%
xxxxx xxxx xxxx xxx% xxx%
--提示:
[root@dns shell04]# echo | awk '{print "第一行"} { print "第二行"} { print "第三行"}''
第一行
第二行
第三行
# free |grep Swap |awk '{print "total\tused\tfree\tused%\tfree%"} {print $2"\t"$3"\t"$4"\t"$3*100/$2"%\t"$4*100/$2"%"} '
total used free used% free%
4096564 0 4096564 0% 100%
================================
--awk外部脚本
脚本的结构
BEGIN {
}
{
}
END {
}
例 :把 awk -F: '{print $1}' /etc/passwd 改成写外部脚本的形式
BEGIN {
FS=":"
}
{
print $1
}
# awk -f 1.awk /etc/passwd
例: 打印字段数大于5的总行数 (用脚本写)
awk -F: 'BEGIN {c=0} {if (NF>5) {c=c+1}} END {print c}' /etc/passwd
BEGIN {
FS=":"
c=0
}
{
NF>5 --这两句用if来写的话 为: if ( NF>5 )
{ c=c+1 } c=c+1
}
END {
print c
}
例:找出目录下的最大的文件和最小的文件,输出平均大小
思路: ls 有一个参数大写字母S,会把文件从大到小排序,排序后,最大文件就是第一行(NR=1),最小文件就是最后一行,平均大小为(累计总大小/NR);注意 grep -v 总计 这句如果是英文系统,就换成grep -v Total
vim 3.awk
BEGIN {
total=0
}
{
if (NR==1)
print "最大文件是:"$NF" 其大小为:"$5
total=total+$5
}
END {
print "最小文件是:"$NF" 其大小为:"$5
print "所有文件平均大小为:"total/NR
}
# ll -S |grep -v total |awk -f 3.awk 最大文件是:shell04.txt 其大小为:7245
最小文件是:1.awk 其大小为:33
所有文件平均大小为:2957.8
-------------------------------
--awk字符匹配
== 完全精确匹配
~ 匹配
!~ 不匹配
完全匹配
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
例:统计/etc/passwd里以/sbin/nologin结束的用户名,把用户名打印出来,并统计个数
--非awk的用法,两条命令
cat /etc/passwd |grep nologin$ |cut -d":" -f1 --打印
cat /etc/passwd |grep nologin$ |cut -d":" -f1 |wc -l --统计个数
# cat /etc/passwd |awk -F: 'BEGIN {a=0} { if ($7=="/sbin/nologin") {print $1; a=a+1} } END {print "其总个数为"a}'
例:倒序排序所有字段(/etc/passwd)
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
可以看到结果倒序排列
=====================================================
sed 流编辑器
sed - stream editor for filtering and trans-
forming text
删除
head -n 5 /etc/passwd |cat -n |sed -e '2d' --指定删除第二行
head -n 5 /etc/passwd |cat -n |sed -e '2,3d' --删除第二行到第三行,中间为逗号,表示范围
head -n 5 /etc/passwd |cat -n |sed -e '1d;5d' --删除第一行和第五行,中间为分号,表示单独的操作
head -n 5 /etc/passwd |cat -n |sed -e '1d;5d;3d'
head -n 5 /etc/passwd |cat -n |sed -e '1d;3,5d'
--利用正则表达式来匹配行
head -n 5 /etc/passwd |cat -n |sed -e '/oo/d' --删除匹配oo的行
head -n 5 /etc/passwd |sed -e '/^root/d' --删除以root开头的行
head -n 5 /etc/passwd |sed -e '/bash$/d' --删除以bash结尾的行
cat /etc/inittab |sed -e '/^$/d' --删除空格行
head -n 5 /etc/passwd |sed -e '/^[a-z]/d'
head -n 5 /etc/passwd |sed -e '/^[a-z]/d' --删除小写字母开头的行,用[a-z]表示
head -n 5 /etc/passwd |sed -e '/^[A-Z]/d'--删除大写字母开头的行,用[A-Z]表示
head -n 5 /etc/passwd |sed -e '/^[a-Z]/d' --删除以字母开头的行,用[a-Z]表示,小写的a到大写的Z
head -n 5 /etc/passwd |sed -e '/^[[:alpha:]]/d' --也是删除以字母开头的
head -n 5 /etc/passwd |sed -e '/^[[:digit:]]/d' --删除以数字开头的
head -n 5 /etc/passwd |sed -e '/^[[:upper:]]/d' --删除以大写字母开头的
head -n 5 /etc/passwd |sed -e '/^[[:lower:]]/d' --删除以小写字母开头的
head -n 5 /etc/passwd |sed -e '/^[[:punct:]]/d' --删除以标点符号开头的
head -n 5 /etc/passwd |sed -e '/^[[:blank:]]/d' --删除以空格开头的
head -n 5 /etc/passwd |sed -e '/^ /d' --同上
head -n 5 /etc/passwd |sed -e '/^\ /d' --同上
cat /etc/inittab |sed '/^#/d;/^$/d'
--删除/etc/inittab的空行和注释
yum install smb* -y
/etc/samba/smb.conf
yum install vsftpd* -y
/etc/vsftpd/vsftpd.conf
yum install sendmail* -y
/etc/mail/sendmail.mc --以dnl开头来注释的
对源文件进行操作需要 -i 参数
练习:sed -i 删除vsftpd.conf,smb.conf,sendmail.mc里所有的注释和空格
# sed -i '/^#/d;/^$/d' /etc/vsftpd/vsftpd.conf
# sed -i '/#/d;/^$/d;/^;/d' /etc/samba/smb.conf
# sed -i '/^dnl /d' /etc/mail/sendmail.mc
打印
head -5 /etc/passwd |sed -e '/root/p' --匹配root的行打印出来,但发现/etc/passwd的前五行也打印出来了
head -5 /etc/passwd |sed -n -e '/root/p' --去除常规打印的信息,只打印匹配的行,要多加一个-n的参数,注意:-n不能加在-e之后,用-ne也可以,但用-en不行
head -5 /etc/passwd |sed -ne '/^root/p'
head -5 /etc/passwd |sed -ne '/nologin$/p'
cat /etc/inittab |sed -ne '/^$/p'
head -5 /etc/passwd |sed -ne '1,4p'
head -5 /etc/passwd |sed -ne '1p;4p'
head -5 /etc/passwd |sed -ne '/^[[:upper:]]/p;/^[a-z]/p' --分别打印大写字母开头的行和小写字母开头的行
head -5 /etc/passwd |sed -ne '/^[[:upper:]]/,/^[a-z]/p' --用正则表达式实现范围打印
head -5 /etc/passwd |sed -ne '/^[[:upper:]]/,/nologin$/p'
=================================================================
格式化输入所有ssh登录成功的信息
[root@li shell04]# sed -n '/Accepted.*from/p' /var/log/secure | awk '{print "*********************************************************"} {print "time\t\thostname\tuser\tip\t\tport\tprotocol"} {print $1"-"$2" "$3"\t"$4"\t\t"$9"\t"$11"\t"$13"\t"$14} {print "*********************************************************"}'
*********************************************************
time hostname user ip port protocol
Jul-15 15:47:20 li root 2.2.2.35 6703 ssh2
*********************************************************
*********************************************************
time hostname user ip port protocol
Jul-15 15:47:27 li root 2.2.2.35 6704 ssh2
*********************************************************
=================================================================
替换
head -5 /etc/passwd |sed -e 's/root/sed/'
head -5 /etc/passwd |sed -e 's/:/@_@/' --把每一行的第一个匹配的字符替换
head -5 /etc/passwd |sed -e 's/:/@_@/g' --后面加一个g,代表全替换
head -5 /etc/passwd |sed -e 's/:/&@_@&/g' --&符号代表前面匹配的字符串
head -5 /etc/passwd |sed -e '2,4s/:/&@_@&/g' --指定替换2到4行
head -5 /etc/passwd |sed -e '1,$s/:/&@_@&/g' --替换所有行,默认不加的话就是替换所有行
head -5 /etc/passwd |sed -e '/^root/,/^adm/s/:/&@_@&/g' --使用正则表达式来表示替换的行范围
head -5 /etc/passwd |sed -e '/^root/s/:/@_@/g;/^adm/s/:/@_@/g' --替换以root开头的行和替换以adm开头的行
练习:
假如一台电脑开机后自动获取IP
写一个脚本
要求:
1,假如获取的IP为2.2.2.X,把其以后都改为静态固定获取这个IP
2,自动把它的主机名改为stationX.cluster.com(X代表获取IP的最后一个数),并加到/etc/hosts里,还要修改/etc/sysconfig/network里的全局主机名;
3,修改ssh端口为2222,日志记录到local5设备,并记录到/var/log/ssh
4,并配置/var/log/ssh每月1号0点轮转一次
5,每月最后一天23点41分对成功登录的ssh信息打印成表的形式并保留成/tmp/ssh_success.txt文件,类似下面的表形式
*********************************************************
time hostname user ip port protocol
Jul-15 15:47:27 li root 2.2.2.35 6704 ssh2
*********************************************************
#!/bin/bash
ip=`ifconfig eth0 |grep Bcast|awk '{print $2}'|awk -F: '{print $2}'`
iptail=`echo $ip |awk -F. '{print $NF}'`
sed -i '/^BOOTPROTO/s/dhcp/static/' /etc/sysconfig/network-scripts/ifcfg-eth0
echo "IPADDR=$ip" >> /etc/sysconfig/network-scripts/ifcfg-eth0
echo "NETMASK=255.255.255.0" >> /etc/sysconfig/network-scripts/ifcfg-eth0
hostname station"$iptail".cluster.com
echo "$ip station$iptail.cluster.com" >> /etc/hosts
sed -i '/^HOSTNAME/d' /etc/sysconfig/network
echo "HOSTNAME=station$iptail.cluster.com" >> /etc/sysconfig/network
=================================================================
使用组或者域进行打印的定位
\(\)是将\( 和 \) 之间的字符串定义为组,并且将匹配这个表达式的保存到一个区域(一个正则表达式最多可以保存9个),它们使用\1到\9来表示
或者使用扩展模式() 直接把括号内的字符串定义为组
# echo "hi,Mr smith.welcome" |sed -e 's/\(.*\),\(.*\)\.\(.*\)/\3,\2,\1/'
welcome,Mr smith,hi
# echo "hi,Mr smith.welcome" |sed -r 's/(.*),(.*)\.(.*)/\3,\2,\1/'
welcome,Mr smith,hi
--使用-r参数使
用扩展模式,在分域时可以去掉\符号,看上去比较简洁
[root@li www]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
将/etc/passwd的第一行进行分域反转
[root@li www]# head -1 /etc/passwd | sed -r 's/(.*):(.*):(.*):(.*):(.*):(.*):(.*)/\7:\6:\5:\4:\3:\2:\1/'
/bin/bash:/root:root:0:0:x:root
把/etc/passwd上下进行反转
# cat -n /etc/passwd |sort -t" " -k 1 -n -r |sed -r 's/(.......)(.*)/\2/'
删除每行的第一个字符
# head -5 /etc/passwd | sed -r 's/(.)(.*)/\2/'
删除每行的第二个字符
head -5 /etc/passwd |sed -r 's/(.)(.)(.*)/\1\3/'
删除每行的第九个字符
head -5 /etc/passwd |sed -r 's/(........)(.)(.*)/\1\3/'
删除倒数第5个字符
head -5 /etc/passwd |sed -r 's/(.*)(.)(....)/\1\3/'
把每行的第5个字符和第8个字符互换,并删除第10个字符
head -5 /etc/passwd |sed -r 's/(....)(.)(..)(.)(.)(.)(.*)/\1\4\3\2\5\7/'
正则达式补充:
a+代表多个a
[a-z]+代表多个小写字母
[A-Z]+代表多个大写字母
[a-Z]+代表多个字母
删除每行的第一个单词
cat /etc/fstab |sed -r 's/([a-Z]+)(.*)/\2/'
cat /etc/fstab |sed -r 's/([a-Z]+)([^a-Z]+)(.*)/\2\3/'
删除每行的第二个单词
cat /etc/fstab |sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/\1\2\4/'
删除每行的最后一个单词
cat /etc/fstab |sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+$)/\1\2\4/'
删除每行的倒数第二个单词
cat /etc/fstab |sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+$)/\1\2\4\5\6/'
=====================================
学习完shell后你应该可以写出下列几大类脚本:
触发型脚本
自动安装型
监控警告型
自动管理型
日志处理型
自动应答型
=============================================================
对apache的日志进行处理
笔记目录下有一个access.log日志文件
处理前格式为:
10.1.1.183 - - [02/Apr/2011:15:36:54 +0800] "GET /shell05/shell05.txt HTTP/1.1" 200 6305 "http://10.1.1.35/shell05/" "Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.0.12) Gecko/2009070811 Red Hat/3.0.12-1.el5_3 Firefox/3.0.12"
处理后格式为:
时间 访问ip 访问文件
2011-apr-02 15:36:54 10.1.1.183 shell05.txt
cat access_log |awk '{print $4"\t"$1"\t"$7}'| awk -F[ '{print $2}'| sed -e 's/:/ /g'|sed -e 's/\// /g'|awk '{print $3","$2","$1","$4":"$5":"$6","$7","$NF}'|sed -r 's/(.*),(.*),(.*),(.*),(.*),(.*)/\1-\2-\3 \4\t\5\t\6/'