Awk总结笔记mysql
90年代 new awk :nawkios
Linux 的是gawk 咱们简化awknginx
# awk [options ] ‘scripts’ file1 file2 ....web
# awk [options ] ‘PATTERN {action }’ file1 file2 ....正则表达式
读入文本先切片以下 切5片sql
每片$n 整行$0shell
每行片数不同centos
内置变量数组
如下为awk内置变量:缓存
ARGC 命令行参数个数
FILENAME 当前输入文档的名称
FNR 当前输入文档的当前记录编号,尤为当有多个输入文档时有用
NR 输入流的当前记录编号
NF 当前记录的字段个数
FS 字段分隔符
OFS 输出字段分隔符,默认为空格
ORS 输出记录分隔符,默认为换行符\n
RS 输入记录分隔符,默认为换行符\n
示例:
[root@centos5 awk]# cat a.txt
welcome to my heart
i am liujianzuo
how are u?
[root@centos5 awk]# awk '{print $1}' a.txt
welcome
i
How
[root@centos5 awk]# df -hP #显示到一行
Filesystem Size Used Avail Use% Mounted on
/dev/sda3 7.1G 3.2G 3.6G 48% /
/dev/sda1 198M 13M 176M 7% /boot
tmpfs 63M 0 63M 0% /dev/shm
/dev/sdb1 99M 6.1M 88M 7% /data
[root@centos5 awk]# df -h|awk '{print $1}'
Filesystem
/dev/sda3
/dev/sda1
tmpfs
/dev/sdb1
相似cut -d
[root@centos5 awk]# awk -F : '{print $1}' /etc/passwd
root
bin
daemon
adm
lp
sync
shutdown
halt
news
uucp
operator
games
gopher
ftp
nobody
nscd
vcsa
pcap
ntp
dbus
[root@centos5 awk]# awk -F : '{print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown
/sbin/halt
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
[root@centos5 awk]# cat a.txt
welcome to my heart
i am liujianzuo
how are u?
[root@centos5 awk]# awk '{print $(NF-2)}' a.txt
to
i
how
[root@centos5 awk]# awk -v FS=: '{print $NF}' /etc/passwd|tail -3
/sbin/nologin
/bin/bash
/bin/bash
[root@centos5 awk]# awk '{print $1 $2}' a.txt
welcometo
iam
howare
[root@centos5 awk]# awk '{print $1,$2}' a.txt
welcome to
i am
how are
[root@centos5 awk]# awk -v OFS=: '{print $1,$2}' a.txt
welcome:to
i:am
how:are
不会自动换行 须要\n
格式符候还能够加修饰符
以下是每一行开始第一列字段是10个字符对其,第二列字段是1个字符对其,默认右对齐
,不会自动换行
[root@centos5 awk]# awk '{printf "%10s,%s",$1,$2}' a.txt
welcome,to i,am how,are[root@centos5 awk]#
[root@centos5 awk]# awk '{printf "%10s,%s\n",$1,$2}' a.txt
welcome,to
i,am
how,are
[root@centos5 awk]# awk '{printf "%-10s,%-s\n",$1,$2}' a.txt
welcome ,to
i ,am
how ,are
[root@centos5 awk]# awk '{printf "%-10s%-s\n",$1,$2}' a.txt
welcome to
i am
how are
[root@centos5 awk]# awk -F : '{printf "%-10s %i\n",$1,$3 > "/dev/stderr" }' /etc/passwd #改变输出流,引号引发来
[root@centos5 awk]# awk -F : '{printf "%-10s %i\n",$1,$3 > "/server/scripts/awk/passwd.log" }' /etc/passwd #改变输出流
[root@centos5 awk]# cat passwd.log
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
news 9
uucp 10
operator 11
games 12
gopher 13
ftp 14
nobody 99
nscd 28
vcsa 69
pcap 77
ntp 38
dbus 81
avahi 70
rpc 32
mailnull 47
smmsp 51
oprofile 16
sshd 74
rpcuser 29
nfsnobody 65534
xfs 43
haldaemon 68
avahi-autoipd 100
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
这里y是种模式
[root@centos5 awk]# awk 'BEGIN{print "a" "b"}'
ab
匹配某一行第一个字段是以root开头的模式咱们就打印第3 4 最后一个字段
[root@centos5 awk]# awk -F : '$1 ~ /^root/ {print $3,$4,$NF}' /etc/passwd
0 0 /bin/bash
for i in read write print;
do
cat file.txt | awk '{ if ($7~/'"$i"'/) {print $0} }'| wc -l ;
done
匹配pation以后是动做以下例子,匹配bash这个模式后动做是打印匹配的包含的所有
# awk [options ] 'PATTERN {action }' file1 file2 ....
[root@centos5 awk]# awk -F : '/bash/ {print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash
oldboy:x:500:500::/home/oldboy:/bin/bash
disdata:x:999:999::/home/disdata:/bin/bash
ayibang:x:1000:1000::/home/ayibang:/bin/bash
[root@centos5 awk]# awk -F : '/bash/ {print $1}' /etc/passwd
root
oldboy
disdata
ayibang
[root@centos5 awk]# awk -F : '$3 >= 500 {print $1}' /etc/passwd
nfsnobody
oldboy
mysql
nginx
nagios
disdata
ayibang
[root@centos5 awk]# awk -F : '$3 >= 500 {print $1,$3}' /etc/passwd
nfsnobody 65534
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
/bash/,/500/
[root@centos5 ceshi]# awk '/bash|500/ {print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
oldboy:x:500:500::/home/oldboy:/bin/bash
disdata:x:999:999::/home/disdata:/bin/bash
ayibang:x:1000:1000::/home/ayibang:/bin/bash
liujianzuo:x:1001:1001::/home/liujianzuo:/bin/bash
[root@centos5 ~]# awk -F: '$3>=500 {print "USERNAME UID";printf "%-15s%s\n",$1,$3}' /etc/passwd #在awk预读每一行的时候,都打印一行
USERNAME UID
nfsnobody 65534
USERNAME UID
oldboy 500
USERNAME UID
mysql 501
USERNAME UID
nginx 502
USERNAME UID
nagios 503
USERNAME UID
disdata 999
USERNAME UID
ayibang 1000
[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME UID"} $3 >= 500 {printf "%-15s%s\n",$1,$3}' /etc/passwd
USERNAME UID
nfsnobody 65534
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
liujianzuo 1001
[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME UID"} {if($3 >= 500) printf "%-15s%s\n",$1,$3}' /etc/passwd
USERNAME UID
nfsnobody 65534
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
liujianzuo 1001
[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME UID"}{printf "%-15s%s\n",$1,$3}' /etc/passwd
USERNAME UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
news 9
uucp 10
operator 11
games 12
gopher 13
ftp 14
nobody 99
nscd 28
vcsa 69
pcap 77
ntp 38
dbus 81
avahi 70
rpc 32
mailnull 47
smmsp 51
oprofile 16
sshd 74
rpcuser 29
nfsnobody 65534
xfs 43
haldaemon 68
avahi-autoipd 100
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
liujianzuo 1001
[root@centos5 ceshi]# awk -F: 'BEGIN{print "USERNAME UID"} {$3>=500;printf "%-15s%s\n",$1,$3}END{printsswd "END"}' /etc/passwd
USERNAME UID
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
news 9
uucp 10
operator 11
games 12
gopher 13
ftp 14
nobody 99
nscd 28
vcsa 69
pcap 77
ntp 38
dbus 81
avahi 70
rpc 32
mailnull 47
smmsp 51
oprofile 16
sshd 74
rpcuser 29
nfsnobody 65534
xfs 43
haldaemon 68
avahi-autoipd 100
oldboy 500
mysql 501
nginx 502
nagios 503
disdata 999
ayibang 1000
liujianzuo 1001
END
[root@centos5 ceshi]# awk -F : '{print $1}' /etc/passwd |head -1
root
[root@centos5 ceshi]# awk -v FS=: '{print $1}' /etc/passwd |head -1
root
[root@centos5 ceshi]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd |head -1
root
若是if后面是好几个条件应该用花括号扩起来
[root@centos5 ~]# awk -F: -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd
8
[root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd
/sbin/nologin
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/bash
/bin/bash
/bin/bash
[root@centos5 ~]# awk -F: '{if ($3>=500) print $NF}' /etc/passwd|wc -l
8
[root@centos5 ceshi]# awk -F: '{if ($3 == 0) print $1,"Admin";else print $1,"Comman user"}' /etc/passwd
root Admin
bin Comman user
daemon Comman user
adm Comman user
lp Comman user
sync Comman user
shutdown Comman user
halt Comman user
mail Comman user
news Comman user
uucp Comman user
operator Comman user
games Comman user
gopher Comman user
ftp Comman user
nobody Comman user
nscd Comman user
vcsa Comman user
pcap Comman user
ntp Comman user
dbus Comman user
avahi Comman user
rpc Comman user
mailnull Comman user
smmsp Comman user
oprofile Comman user
sshd Comman user
rpcuser Comman user
nfsnobody Comman user
xfs Comman user
haldaemon Comman user
avahi-autoipd Comman user
oldboy Comman user
mysql Comman user
nginx Comman user
nagios Comman user
disdata Comman user
ayibang Comman user
liujianzuo Comman user
[root@centos5 ~]# awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd
root
x
0
bin
x
1
daemon
x
2
adm
x
3
lp
x
4
sync
x
5
shutdown
x
6
halt
x
7
x
8
news
x
9
uucp
x
10
operator
x
11
games
x
12
gopher
x
13
ftp
x
14
nobody
x
99
nscd
x
28
vcsa
x
69
pcap
x
77
ntp
x
38
dbus
x
81
avahi
x
70
rpc
x
32
mailnull
x
47
smmsp
x
51
oprofile
x
16
sshd
x
74
rpcuser
x
29
nfsnobody
x
65534
xfs
x
43
haldaemon
x
68
avahi-autoipd
x
100
oldboy
x
500
mysql
x
501
nginx
x
502
nagios
x
503
disdata
x
999
ayibang
x
1000
liujianzuo
x
1001
Awk能够加pattion 模式的意思,若是不匹配pattion意指其会每行都匹配。
[oldboy@centos5 ~]$ awk -F: '$1 !~ /^root/{i=1;while (i<=2) {print $i;i++}}' /etc/passwd
bin
x
daemon
x
adm
x
lp
x
sync
x
shutdown
x
halt
x
x
news
x
uucp
x
operator
x
games
x
gopher
x
ftp
x
nobody
x
nscd
x
vcsa
x
pcap
x
ntp
x
dbus
x
avahi
x
rpc
x
mailnull
x
smmsp
x
oprofile
x
sshd
x
rpcuser
x
nfsnobody
x
xfs
x
haldaemon
x
avahi-autoipd
x
oldboy
x
mysql
x
nginx
x
nagios
x
disdata
x
ayibang
x
liujianzuo
X
例如我想取第第奇数个字段。咱们递增i+=2便可
[oldboy@centos5 ~]$ awk -F: '$3 >= 500{i=1;while (i<=4) {print $i;i+=2}}' /etc/passwd
Nfsnobody #第一列
65534 #第三列
Oldboy #第一列
500 #第三列
mysql
501
nginx
502
nagios
503
disdata
999
ayibang
1000
liujianzuo
1001
do-while 不管条件如何,首先会循环一遍,当条件一知足就会退出
[root@centos5 awk]# awk 'BEGIN{i=1;while (i<=100) {sum+=i;print sum;i++}}' |tail -1
5050
awk 'BEGIN{i=1;do {sum+=i;print sum;i++}while(i<=100)}'|tail -1
5050
awk 'BEGIN{i=1;do {sum=sum+i;print sum;i++}while(i<=100)}'|tail -1
5050
awk 'BEGIN{i=1;do {sum+=i;i++}while(i<=100) print sum}'
【元婴】北京-吴兆 2015/1/11 17:53:30
循环中不输出,最后输出结构就好了……
cat filename | nawk -F " " '{for (i=4;i<=NF;i++)printf("%s ", $i);print ""}' 字段不换行 printf
[root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=NF;i+=2) print $i}' /etc/passwd
awk -F: '$3>=500{for (i=1;i<=NF;i+=2) printf("%s ", $i);print ""}' /etc/passwd
nfsnobody
65534
Anonymous NFS User
/sbin/nologin
oldboy
500
/bin/bash
mysql
501
/sbin/nologin
nginx
502
/sbin/nologin
nagios
503
/sbin/nologin
disdata
999
/bin/bash
ayibang
1000
/bin/bash
liujianzuo
1001
/bin/bash
for打印第奇数个字段
[root@centos5 awk]# awk -F: '$3>=500{for (i=1;i<=5;i+=2) print $i}' /etc/passwd
nfsnobody
65534
Anonymous NFS User
oldboy
500
mysql
501
nginx
502
nagios
503
disdata
999
ayibang
1000
liujianzuo
1001
[root@centos5 awk]# awk 'BEGIN{for (i=i;i<=100;i++) {j=j+i;print j}}'|tail -1
5050
[root@ayibang-server /server/scripts]# awk 'BEGIN{j=0;for (i=1;i<=100;i++) j+=i;{print j}}'
5050
内置变量
如下为awk内置变量:
ARGC 命令行参数个数
FILENAME 当前输入文档的名称
FNR 当前输入文档的当前记录编号,尤为当有多个输入文档时有用
NR 输入流的当前记录编号
NF 当前记录的字段个数
FS 字段分隔符
OFS 输出字段分隔符,默认为空格
ORS 输出记录分隔符,默认为换行符\n
RS 输入记录分隔符,默认为换行符\n
示例:
[liujianzuo@w2 scripts]$ for n in {06..26};do for i in `ls -l /data1/logs/qr* |awk '{print $NF}'`;do wc -l $i|awk -F . '$NF ~ /201507'${n}'/{print $0}';done;done 1 /data1/logs/qrscene_51pro_gz.log.20150707
6 /data1/logs/qrscene_51pro_hz.log.20150707
2 /data1/logs/qrscene_51pro_nj.log.20150707
3 /data1/logs/qrscene_51pro_qd.log.20150707
1 /data1/logs/qrscene_51pro_sh.log.20150707
6 /data1/logs/qrscene_51pro_wh.log.20150707
1 /data1/logs/qrscene_51pro_xa.log.20150707
1 /data1/logs/qrscene_51pro_zz.log.20150707
4 /data1/logs/qrscene_cq_dm.log.20150707
5 /data1/logs/qrscene_cq_sl.log.20150707
17 /data1/logs/qrscene_cs_dm.log.20150707
1 /data1/logs/qrscene_gz_dm.log.20150707
1 /data1/logs/qrscene_gz_szi.log.20150707
6 /data1/logs/qrscene_hz_dm.log.20150707
9 /data1/logs/qrscene_mlyh.log.20150707
2 /data1/logs/qrscene_nj_dm.log.20150707
3 /data1/logs/qrscene_nj_sl.log.20150707
1 /data1/logs/qrscene_qd_szi.log.20150707
1 /data1/logs/qrscene_xa_szi.log.20150707
14 /data1/logs/qrscene_xiaomi.log.20150707
26 /data1/logs/qrscene_xz.log.20150707
4 /data1/logs/qrscene_zz_dm.log.20150707
3 /data1/logs/qrscene_15suit.log.20150708
5 /data1/logs/qrscene_51pro_bj.log.20150708
1 /data1/logs/qrscene_51pro_gz.log.20150708
5 /data1/logs/qrscene_51pro_hz.log.20150708
19 /data1/logs/qrscene_51pro_qd.log.20150708
1 /data1/logs/qrscene_51pro_wh.log.20150708
。。。。。略去n行
http://oldboy.blog.51cto.com/2561410/760192
问题为:
4)已知:/etc/hosts的内容为
192.168.1.11 oldboy11.etiantian.org
192.168.1.21 oldboy21.etiantian.org
192.168.1.31 oldboy31.etiantian.org
#192.168.1.111 oldboy111.etiantian.org
请用shell脚本实现,怎么才能在输入IP后找到/etc/hosts里对应的惟一的hostname?
解答:
法1)脚本过滤法
[root@old_boy scripts]# cat judgehost.sh
#!/bin/bash
echo "please input ip address:"
read ip
[ -n "`grep "$ip " /etc/hosts`" ] && \ #注意前面的过滤条件结尾带有空格。
echo "The hostname is: `grep "$ip " /etc/hosts |awk '{print $2}'`" || \
echo "The ip is invalid"
提示:
1)这是一个grep过滤加条件判断的实现语法:
2)条件判断语法为[ -n "ddd" ] && echo 1 || echo 0
3)[ -n "`grep "$ip " /etc/hosts`" ] && \ #注意前面的过滤条件结尾带有空格。这里啊,是为了排除下面的重复状况
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org
----------------我是每种方法分隔符---------------
法2)脚本精确匹配法:
#!/bin/bash
#author oldboy
#qq 31333741
#judge input
if [ $# -ne 1 ]
then
echo "input error!"
exit 1
fi
flag=0
exec < /etc/hosts
while read line
do
if [ "$1" = "`echo $line|awk '{print $1}'`" ]
then
flag=1
echo "the $1 's hostname is `echo $line|awk '{print $2}'`"
break;
fi
done
[ $flag -eq 0 ] && echo " sorrry,not find $1 's hostname!"
提示:此题,请你们学习while的用法及设置flag的思路。
执行结果:
[root@old_boy scripts]# sh oldboy.sh 192.168.1.11
the 192.168.1.11 's hostname is oldboy11.etiantian.org
[root@old_boy scripts]# sh oldboy.sh 192.168.1.21
the 192.168.1.21 's hostname is oldboy21.etiantian.org
[root@old_boy scripts]# sh oldboy.sh 192.168.1.311
sorrry,not find 192.168.1.311 's hostname!
----------------我是每种方法分隔符---------------
特别提示:下面的方法中,老男孩老师大量的使用了awk的不一样方法来实现一样的功能,来告诉你们,awk是很强大的, 但愿同窗们能按照老师的教学要求精通之。
法3)awk精确匹配:
准备:
[root@old_boy scripts]# tail -4 /etc/hosts
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org
192.168.1.21 oldboy21.etiantian.org
192.168.1.31 oldboy31.etiantian.org
脚本:
[root@old_boy scripts]# cat awkhost1.sh
awk 'BEGIN {a="'$1'"} {if($1==a) print $2; }' /etc/hosts
执行结果:
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.31
oldboy31.etiantian.org
[root@old_boy scripts]# sh awkhost1.sh 192.168.1.11
oldboy11.etiantian.org
提示:注意a="'$1'"的用法,$1为命令行传参。awk程序中调用系统变量的方法a="'$1'"。
----------------我是每种方法分隔符---------------
法4)awk精确匹配法
[root@old_boy scripts]# cat awkhost2.sh
awk '{if($1=="'$1'") print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# awkhost2.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost2.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost2.sh 192.168.1.311
----------------我是每种方法分隔符---------------
法5)awk过滤法
[root@old_boy scripts]# cat awkhost4.sh
awk '/'"${1} "'/''{print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# awkhost4.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost4.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost4.sh 192.168.1.31
oldboy31.etiantian.org
提示:除了语法外,这道题有个学问,就是过滤时传参结尾要带个空格,这样才能过滤重复IP的状况
如:
192.168.1.11 oldboy11.etiantian.org
192.168.1.111 oldboy111.etiantian.org
----------------我是每种方法分隔符---------------
法6)awk过滤法
[root@old_boy scripts]# cat awkhost5.sh
awk '{if($1~/'$1'/) print $2}' /etc/hosts ##若是文件第一列包含命令行第一个参数字符则打印第二列
执行结果:
[root@old_boy scripts]# awkhost5.sh 192.168.1.31
oldboy31.etiantian.org
[root@old_boy scripts]# awkhost5.sh 192.168.1.11
oldboy11.etiantian.org
oldboy111.etiantian.org ------>这里有bug了。
[root@old_boy scripts]# awkhost5.sh 192.168.1.21
oldboy21.etiantian.org
改进下来排除bug:
[root@old_boy scripts]# cat awkhost5-1.sh
awk '{if($1~/'$1' /) print $2}' /etc/hosts ==>用上面加空格的思路不对。
[root@old_boy scripts]# cat awkhost5-1.sh
awk '{if($1~/'$1'$/) print $2}' /etc/hosts #增长一个正则表达式$
执行结果:
[root@old_boy scripts]# awkhost5-1.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# awkhost5-1.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# awkhost5-1.sh 192.168.1.31
oldboy31.etiantian.org
----------------我是每种方法分隔符---------------
法7)awk -v精确匹配法
命令行测试:
[root@old_boy scripts]# awk -v p=192.168.1.21 '$1 == p{print $2}' /etc/hosts
oldboy21.etiantian.org
[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p{print $2}' /etc/hosts
oldboy11.etiantian.org
[root@old_boy scripts]# awk -v p=192.168.1.11 '$1 == p {print $2}' /etc/hosts
oldboy11.etiantian.org
实际脚本:
[root@old_boy scripts]# cat awkhost6.sh
#!/bin/bash
#p=$1
#awk -v p="$p" '$1 == p{print $2}' /etc/hosts
awk -v p="$1" '$1 == p{print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# sh awkhost6.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# sh awkhost6.sh 192.168.1.21
oldboy21.etiantian.org
提示:
1)传参非awk程序,所以写法p="$1"
2)man awk
-v var=val
--assign var=val
Assign the value val to the variable var, before execution of the program begins. Such vari-
able values are available to the BEGIN block of an AWK program.
----------------我是每种方法分隔符---------------
法8:精确匹配简单的写法
[root@old_boy scripts]# cat awkhost9.sh
awk '$1 == "'$1'" {print $2}' /etc/hosts
执行结果:
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.11
oldboy11.etiantian.org
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.21
oldboy21.etiantian.org
[root@old_boy scripts]# sh awkhost9.sh 192.168.1.31
oldboy31.etiantian.org
特别提示:这里老男孩老师大量的使用了awk的不一样方法来实现一样的功能,很强大吧,
但愿同窗们能按照老师的教学要求精通之。
数组就是变量的即集合体
Shell中的打印 echo ${A["x"]} 须要${}才能输出变量,而awk则不用
下标能够是任意字符,可是咱们要将字符用引号引发来,以避免被误认为变量
以下
[root@centos5 ~]# awk 'BEGIN{A[x]='hello';A[y]='world';print A[x]}'
[root@centos5 ~]# awk 'BEGIN{A["x"]='hello';A["y"]='world';print A[x],A["y"]}'
[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A[x],A["y"]}'
world
[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";print A["x"],A["y"]}'
hello world
Awk的数组不能跟shell的数组同样,不能一一遍历,它的元素不都是数字,有多是字符串或者字段
第二个是for循环是awk的遍历,这里面的ARRAY是数组,A是咱们定义的变量是数组的下标数字0 1 2 3 。。。 A保存的是咱们数组ARRAY的下标名字
例如
[root@centos5 ~]# awk 'BEGIN{A["x"]="hello";A["y"]="world";for (B in A) print A[B]}' #这里的B是定义的变量就是A数组的下标号,咱们遍历A数组,打印全部的元素。B保存的是A数组的下标名字
hello
world
Tcp状态有好多种,最后一列,咱们用awk实现统计每种状态的链接数 后面有解释
[root@centos5 ~]# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:5666 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:199 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:624 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22929 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:52113 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1012 0.0.0.0:* LISTEN
tcp 0 0 192.168.92.132:52113 192.168.92.1:49262 ESTABLISHED
tcp 0 0 :::52113 :::* LISTEN
Awk的数组组成:数组名字,数组下标,数组元素,数组元素的值。
S[$NF]++ 意思是咱们这个数组S,咱们取最后一列做为这个数组的下标,所以这个数组就是S[LISTEN] S[ESTABLISHED],每读取一行,相同元素会叠加
这里A是数组S的下标名称,而数组S的下标名称是TIME_WAIT CLOSE_WAIT FIN_WAIT1 ESTABLISHED 等等。For循环是遍历的这几种,因此A就表明这几个名称,而S[A]则表明数组元素的值
[ayibang@db2 ~]$ netstat -ant|awk '$1~/tcp/{S[$NF]++}END{for (A in S) print A,S[A]}'
TIME_WAIT 1789
CLOSE_WAIT 38
FIN_WAIT1 6
ESTABLISHED 94
SYN_RECV 3
LAST_ACK 3
LISTEN 23
[ayibang@db2 ~]$ ss -ant |awk '{S[$1]++}END{for (A in S) printf "%4s,%4s\n",S[A],A}'
8,LAST-ACK
3,SYN-RECV
292,ESTAB
1,State
4,FIN-WAIT-1
3,CLOSING
8,FIN-WAIT-2
6469,TIME-WAIT
41,CLOSE-WAIT
23,LISTEN
[root@centos5 ~]# awk -F: '$NF!~/^$/{SHELL[$NF]++}END{for(A in SHELL) printf "%16s:%s\n",A,SHELL[A]}' /etc/passwd
/sbin/shutdown:1
/bin/bash:5
/sbin/nologin:30
/sbin/halt:1
/bin/sync:1
[root@db2 logs]# awk '{IP[$1]++}END{for (A in IP) printf "%20s:%5s\n",A,IP[A]}' access_www.log |sort -rn|head
223.9.2.89: 37
223.68.131.168: 31
223.243.41.89: 1
223.240.233.91: 34
223.223.194.23: 50
223.223.194.215: 16
223.167.19.183: 65
223.166.112.132: 1
223.104.5.30: 69
223.104.5.2: 2
split($5,client,":")含义以下
ه内置函数split 先把第五个字段,以:为分隔符,切割新的字段,保存成client数组,
IP[client[1]]++}END{for (i in IP){print IP[i],i}}'
以新的IP数组,client数组第一列为新数组IP下标,最后作作求和,统计个数
split是函数 用小括号…………
[root@db2 ~]# netstat -ant|awk '/:80/{split($5,client,":");IP[client[1]]++}END{for (i in IP){print IP[i],i}}'|sort -rn |head
10 116.247.112.153
6 210.22.62.180
6 123.125.65.237
5 123.138.215.24
3 221.237.44.110
3 111.202.0.53
3 106.2.195.214
2 117.79.81.51
2 101.80.175.17
2 0.0.0.0
a文件
11 23
13 23
43 56
b文件
11 43
45 455
32 23
输出结果以下
22 66
58 478
75 79
解答:
awk '{a[FNR]+=$1;b[FNR]+=$2} END{for(i in a){print a[i],b[i]}}' cc1.log cc2.log
awk '{n=FNR;a[n]+=$1;b[n]+=$2} END{for(i=1;i<=n;i++){print a[i],b[i]}}' cc1.log cc2.log
awk '{n=FNR;a[n]+=$1;b[n]+=$2; if(NR > n) print a[n],b[n]}' cc1.log cc2.log
awk '{n=FNR;a[n]+=$1;b[n]+=$2} NR > n {print a[n],b[n]}' cc1.log cc2.log
awk '{if(NR == FNR){a[NR]=$1;b[NR]=$2}else{print $1+a[FNR],$2+b[FNR]}}' cc1.log cc2.log
awk 'NR==FNR {a[NR]=$1;b[NR]=$2;next} {print $1+a[FNR],$2+b[FNR]}' cc1.log cc2.log
paste cc1.log cc2.log |awk '{print $1+$3,$2+$4}'
awk 'NR == FNR{a[i]=$1;b[i]=$2;i++} NR>FNR{print $1+a[j],$2+b[j];j++}' cc1.log cc2.log
20150418周末小题
原始数据:
17/Apr/2015:09:29:24 +0800
17/Apr/2015:09:30:26 +0800
17/Apr/2015:09:31:56 +0800
18/Apr/2015:09:34:12 +0800
18/Apr/2015:09:35:23 +0800
19/Apr/2015:09:23:34 +0800
19/Apr/2015:09:22:21 +0800
20/Apr/2015:09:45:22 +0800
指望结果:
2015-04-17 09:29:24+0800
2015-04-17 09:30:26+0800
2015-04-17 09:31:56+0800
2015-04-18 09:34:12+0800
2015-04-18 09:35:23+0800
2015-04-19 09:23:34+0800
2015-04-19 09:22:21+0800
2015-04-20 09:45:22+0800
解决实践:来自运维21期悠久之翼 群内分享
[root@web01 ~]# cat oldboy.txt
17/Apr/2015:09:29:24 +0800
17/Apr/2015:09:30:26 +0800
17/Apr/2015:09:31:56 +0800
18/Apr/2015:09:34:12 +0800
18/Apr/2015:09:35:23 +0800
19/Apr/2015:09:23:34 +0800
19/Apr/2015:09:22:21 +0800
20/Apr/2015:09:45:22 +0800
[root@web01 ~]# awk '{sub(/Apr/,"04");split($0,array,"[/: ]") ;printf("%s-%s-%s %s:%s:%s%s\n",array[3],array[2],array[1],array[4],array[5],array[6],array[7])}' oldboy.txt
2015-04-17 09:29:24+0800
2015-04-17 09:30:26+0800
2015-04-17 09:31:56+0800
2015-04-18 09:34:12+0800
2015-04-18 09:35:23+0800
2015-04-19 09:23:34+0800
2015-04-19 09:22:21+0800
2015-04-20 09:45:22+0800
1. sub函数
[root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'sub(/-/,"",$4)'
a b c 201111-22 a:d
2. gsub函数
[root@nhserver1 10]# echo "a b c 2011-11-22 a:d" | awk 'gsub(/-/,"",$4)'
a b c 20111122 a:d
sub函数只实现第一个位置的替换,gsub函数实现全局的替换。
Split切割是第一列下表是1
[root@web01 ~]# sed -nr 's#(..)/(...)/(....):(..):(..):(..) (.*)#\3-\2-\1 \4:\5:\6\7#;s#Apr#04#p' oldboy.txt
2015-04-17 09:29:24+0800
2015-04-17 09:30:26+0800
2015-04-17 09:31:56+0800
2015-04-18 09:34:12+0800
2015-04-18 09:35:23+0800
2015-04-19 09:23:34+0800
2015-04-19 09:22:21+0800
2015-04-20 09:45:22+0800
. 是一个字符, s是替换 p打印
在编写shell脚本的过程当中,咱们常常须要使用sed流编辑器和awk对文本文件进行处理。
sed 是一种在线编辑器,它一次处理一行内容。sed是非交互式的编辑器。它不会修改文件,除非使用shell重定向来保存结果。默认状况下,全部的输出行都被打印到屏幕上。
sed编辑器逐行处理文件(或输入),并将结果发送到屏幕。具体过程以下:首先sed把当前正在处理的行保存在一个临时缓存区中(也称为模式空间),而后处理临时缓冲区中的行,完成后把该行发送到屏幕上。sed每处理完一行就将其从临时缓冲区删除,而后将下一行读入,进行处理和显示。处理完输入文件的最后一行后,sed便结束运行。
前面说到sed不会修改文件,那么如今咱们能够知道是为何了?是由于sed把每一行都存在临时缓冲区中,对这个副本进行编辑,因此不会修改原文件。
补充知识:
在使用sed的过程当中,咱们常常会听到“定址”,那么什么是“定址”呢?
定址用于决定对哪些行进行编辑。地址的形式能够是数字、正则表达式、或两者的结合。若是没有指定地址,sed将处理输入文件的全部行。
一、地址是一个数字,则表示行号;是“$"符号,则表示最后一行。
例如:
[plain] view plaincopy
二、只显示指定行范围的文件内容
例如:
[plain] view plaincopy
三、地址是逗号分隔的,那么须要处理的地址是这两行之间的范围(包括这两行在内)。范围能够用数字、正则表达式、或两者的组合表示。
例如:
[plain] view plaincopy
sed命令告诉sed如何处理由地址指定的各输入行,若是没有指定地址则处理全部的输入行。
一、sed命令
命令 |
功能 |
a\ |
在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行 |
c\ |
用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行 |
i\ |
在当前行以前插入文本。多行时除最后一行外,每行末尾需用"\"续行 |
d |
删除行 |
h |
把模式空间里的内容复制到暂存缓冲区 |
H |
把模式空间里的内容追加到暂存缓冲区 |
g |
把暂存缓冲区里的内容复制到模式空间,覆盖原有的内容 |
G |
把暂存缓冲区的内容追加到模式空间里,追加在原有内容的后面 |
l |
列出非打印字符 |
p |
打印行 |
n |
读入下一输入行,并从下一条命令而不是第一条命令开始对其的处理 |
q |
结束或退出sed |
r |
从文件中读取输入行 |
! |
对所选行之外的全部行应用命令 |
s |
用一个字符串替换另外一个 |
g |
在行内进行全局替换 |
w |
将所选的行写入文件 |
x |
交换暂存缓冲区与模式空间的内容 |
y |
将字符替换为另外一字符(不能对正则表达式使用y命令) |
二、sed选项
选项 |
功能 |
-e |
进行多项编辑,即对输入行应用多条sed命令时使用 |
-n |
取消默认的输出 |
-f |
指定sed脚本的文件名 |
与grep同样,sed也支持特殊元字符,来进行模式查找、替换。不一样的是,sed使用的正则表达式是括在斜杠线"/"之间的模式。
若是要把正则表达式分隔符"/"改成另外一个字符,好比o,只要在这个字符前加一个反斜线,在字符后跟上正则表达式,再跟上这个字符便可。
例如:
[plain] view plaincopy
经常使用的正则表达式以下:
元字符 |
功能 |
示例 |
^ |
行首定位符 |
/^my/ 匹配全部以my开头的行 |
$ |
行尾定位符 |
/my$/ 匹配全部以my结尾的行 |
. |
匹配除换行符之外的单个字符 |
/m..y/ 匹配包含字母m,后跟两个任意字符,再跟字母y的行 |
* |
匹配零个或多个前导字符 |
/my*/ 匹配包含字母m,后跟零个或多个y字母的行 |
[] |
匹配指定字符组内的任一字符 |
/[Mm]y/ 匹配包含My或my的行 |
[^] |
匹配不在指定字符组内的任一字符 |
/[^Mm]y/ 匹配包含y,但y以前的那个字符不是M或m的行 |
.. |
保存已匹配的字符 |
1,20s/youself/\1r/ 标记元字符之间的模式,并将其保存为标签1,以后可使用\1来引用它。最多能够定义9个标签,从左边开始编号,最左边的是第一个。此例中,对第1到第20行进行处理,you被保存为标签1,若是发现youself,则替换为your。 |
& |
保存查找串以便在替换串中引用 |
s/my/**&**/ 符号&表明查找串。my将被替换为**my** |
\< |
词首定位符 |
/\<my/ 匹配包含以my开头的单词的行 |
\> |
词尾定位符 |
/my\>/ 匹配包含以my结尾的单词的行 |
x\{m\} |
连续m个x |
/9\{5\}/匹配包含连续5个9的行 |
x\{m,\} |
至少m个x |
/9\{5,\}/ 匹配包含至少连续5个9的行 |
x\{m,n\} |
至少m个,但不超过n个x |
/9\{5,7\}/ 匹配包含连续5到7个9的行 |
sed不向grep同样,无论是否找到指定的模式,它的退出状态都是0。只有当命令存在语法错误时,sed的退出状态才不是0。
一、p命令
命令p用于显示模式空间的内容。默认状况下,sed把输入行打印在屏幕上,选项-n用于取消默认的打印操做。当选项-n和命令p同时出现时,sed可打印选定的内容。
例子:
[plain] view plaincopy
二、d命令
命令d用于删除输入行。sed先将输入行从文件复制到模式空间里,而后对该行执行sed命令,最后将模式空间里的内容显示在屏幕上。若是发出的是命令d,当前模式空间里的输入行会被删除,不被显示。
例子:
[plain] view plaincopy
三、s命令
例子:
[plain] view plaincopy
四、e选项
-e是编辑命令,用于sed执行多个编辑任务的状况下。在下一行开始编辑前,全部的编辑动做将应用到模式缓冲区中的行上。
例子:
[plain] view plaincopy
五、r命令
r命令是读命令。sed使用该命令将一个文本文件中的内容加到当前文件的特定位置上。
例如:
[plain] view plaincopy
六、w命令
例子:
[plain] view plaincopy
七、a\ 命令
a\ 命令是追加命令,追加将添加新文本到文件中当前行(即读入模式缓冲区中的行)的后面。所追加的文本行位于sed命令的下方另起一行。若是要追加的内容超过一行,则每一行都必须以反斜线结束,最后一行除外。最后一行将以引号和文件名结束。
例子:
[plain] view plaincopy
八、i\ 命令
i\ 命令是在当前行的前面插入新的文本。
九、c\ 命令
sed使用该命令将已有文本修改为新的文本。
十、n命令
sed使用该命令获取输入文件的下一行,并将其读入到模式缓冲区中,任何sed命令都将应用到匹配行紧接着的下一行上。
例如:
[plain] view plaincopy
注:若是须要使用多条命令,或者须要在某个地址范围内嵌套地址,就必须用花括号将命令括起来,每行只写一条命令,或这用分号分割同一行中的多条命令。
十一、y命令
该命令与UNIX/Linux中的tr命令相似,字符按照一对一的方式从左到右进行转换。例如,y/abc/ABC/将把全部小写的a转换成A,小写的b转换成B,小写的c转换成C。
例如:
[plain] view plaincopy
十二、q命令
q命令将致使sed程序退出,再也不进行其它的处理。
[plain] view plaincopy
1三、h命令和g命令
为了更好说明这两个命令,咱们先建立以下的文本文件:
[plain] view plaincopy
[plain] view plaincopy
补充知识点:sed特殊用法
[plain] view plaincopy
一、从文件读入命令
[plain] view plaincopy
sed.sh文件内容:
[plain] view plaincopy
二、直接运行脚本 ./sed.sh /etc/passwd
[plain] view plaincopy
一、用sed 输出本身的IP 地址
[plain] view plaincopy
二、在sed的命令行中引用shell变量时要使用双引号,而不是一般所用的单引号。下面是一个根据name变量的内容来删除named.conf文件中zone段的脚本:
name='zone\ "localhost"'
[plain] view plaincopy
三、保持和获取:h命令和G命令
[plain] view plaincopy
在sed处理文件的时候,每一行都被保存在一个叫模式空间的临时缓冲区中,除非行被删除或者输出被取消,不然全部被处理的行都将打印在屏幕上。接着模式空间被清空,并存入新的一行等待处理。在这个例子里,匹配test的行被找到后,将存入模式空间,h命令将其复制并存入一个称为保持缓存区的特殊缓冲区内。第二条语句的意思是,当到达最后一行后,G命令取出保持缓冲区的行,而后把它放回模式空间中,且追加到如今已经存在于模式空间中的行的末尾。在这个例子中就是追加到最后一行。简单来讲,任何包含test的行都被复制并追加到该文件的末尾。
四、保持和互换:h命令和x命令
[plain] view plaincopy
互换模式空间和保持缓冲区的内容。也就是把包含test与check的行互换。
1,删除文件每行的第一个字符。
[plain] view plaincopy
2,删除文件每行的第二个字符。
[plain] view plaincopy
3,删除文件每行的最后一个字符。
[plain] view plaincopy
4,删除文件每行的倒数第二个字符。
[plain] view plaincopy
5,删除文件每行的第二个单词。
[plain] view plaincopy
6,删除文件每行的倒数第二个单词。
[plain] view plaincopy
7,删除文件每行的最后一个单词。
[plain] view plaincopy
8,交换每行的第一个字符和第二个字符。
[plain] view plaincopy
9,交换每行的第一个单词和第二个单词。
[plain] view plaincopy
10,交换每行的第一个单词和最后一个单词。
[plain] view plaincopy
11,删除一个文件中全部的数字。
[plain] view plaincopy
12,删除每行开头的全部空格。
[plain] view plaincopy
13,用制表符替换文件中出现的全部空格。
[plain] view plaincopy
14,把全部大写字母用括号()括起来。
[plain] view plaincopy
15,打印每行3次。
[plain] view plaincopy
16,隔行删除。
[plain] view plaincopy
17,把文件从第22行到第33行复制到第44行后面。
[plain] view plaincopy
18,把文件从第22行到第33行移动到第44行后面。
[plain] view plaincopy
19,只显示每行的第一个单词。
[plain] view plaincopy
20,打印每行的第一个单词和第三个单词。
[plain] view plaincopy
21,将格式为 mm/yy/dd 的日期格式换成 mm;yy;dd
[plain] view plaincopy
22, 逆向输出
[plain] view plaincopy