linux shell篇(五)正则表达式
时间:2016-06-29 11:14:44
收藏:0
阅读:1348
一.正则表达式:
正则表达式 RE 、 Regular Expression
是一种字符模式,是在匹配文本时,使用一些特殊符号,匹配到用户想要的东西
字符模式:
普通字符:没有任何特殊含义的字符
元字符:具有特殊含义的字符 ^ $ * . [] () {}
正则表达式一般是夹在双斜线之间的 如:/^abc/等
介绍正则表达式元字符
元字符 功能 例子 匹配结果
^ 行首定位符 /^root/ 匹配以root开头的行
$ 行尾定位符 /sh$/ 匹配以sh结尾的行
. 匹配任意单个字符(除了换行符) /l.ve/ 匹配live、love、... ...
* 前导符
匹配0个或者多个它前面的模式 /l*ve/ 匹配ve、lve、llve、... ...
.* 匹配0到多个任意字符
[] 匹配一组字符中的任意一个 /l[ioIO]ve/ 匹配live、love、lIve、lOve
[x-y] 匹配一段范围中的任意一个 /l[o-z]ve/ 匹配love、lpve、lqve、... ...、lzve
[0-9] 数字
[a-z] 小写字母
[A-Z] 大写字母
[a-z0-9] 小写字母或数字
[-+*/] +-*/ 四则运算
[a-Z] 字母
[^] 表示取反 /^[^abc]ve/ 匹配除了ave、bve、cve以外的三个字符的字符串
[^0-9] 不是数字
\ 用于转义元字符的 /93\.4/ 匹配93.4
\< 词首定位符 /\<bin/ 匹配bin、binary、... ...
\> 词尾定位符 /sh\>/ 匹配bash、csh、ksh、... ...
rootfs
模式的重复{}
x\{m\} x是字符或者字符串,m是数字,表示次数
匹配x出现m次 /a\{3\}/ 匹配到aaa
x\{m,\} 匹配x出现至少m次 /a\{3,\}/ 匹配aaa、aaaa、aaaaaaaa、aaaaaaa、... ...
x\{m,n\} 匹配x出现m次到n次 /a\{3,5\}/ 匹配aaa、aaaa、aaaaa
(root)
(a+(b-c)*d)
\(...\) 分组、标签
& \1 \2
/\(love\)/ \1r
\(root\).*\(bin\).*\2\1 \1ly
a and b
\(a\) and \(b\) ==> \2 and \1
二.正则表达式用法
(一).vim与正则表达式
1、查找替换(letter) tom换成mary
~# vim letter
:%s/\<[Tt]om\>/mary/ ——> tom Tom
2、行首行尾 picnic
/^love
/love$
3、任意字符 picnic
/l.ve
4、前导符 picnic
/o*v
5、范围 picnic
/love[a-z]
6、取反 picnic
/love[^a-z]
7、综合 invite
/^[A-Z]..$ 匹配Dan这一行
/^[A-Z][a-z]*.*3[0-5] 匹配到There are around 30 to 35
//由此可以看出,正则表达式执行的是最大匹配
8、标签
:%s/\(Ginger\) and \(Larry\)/\2 and \1/
:%s/\(Ginger\)\(.*\)\(Larry\)/\3\2\1/
s@@@ s### s%%% s/// 等价的
(二).grep与正则表达式
GREP —— Global Regular Expression Print
好处:非交互
不影响原文件内容,目的就是过滤出用户感兴趣的内容
命令格式
grep [选项] "正则表达式" 文件列表
grep执行状态返回值三种
0:该文件中搜索到了匹配行
1:该文件中未搜索到匹配行
2: 搜索的文件不存在
~# grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
~# echo $?
0
~# grep "roooot" /etc/passwd
~# echo $?
1
~# grep "root" /etc/passwd1
grep: /etc/passwd1: No such file or directory
~# echo $?
2
grep基本使用
设定别名
#alias grep=‘grep --color=auto‘
# vim /etc/bashrc
1、--color 带颜色显示匹配到的关键字
~# grep --color "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
2、-i 忽略大小写
~# cat pass
Root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
~# grep "root" pass --color
Root:x:0:0:root:/root:/bin/bash
~# grep -i "root" pass --color
Root:x:0:0:root:/root:/bin/bash
3、-v 取反
~# grep -v "nologin" /etc/passwd //打印不包含nologin的行
4、^
打印/root/.bashrc文件中的注释行
~# grep ^# /root/.bashrc
打印/etc/inittab文件中的非注释行
~# grep -v ^# /etc/inittab
id:5:initdefault:
5、$
显示passwd文件中以bash结尾的行
~# grep bash$ /etc/passwd
6、^$ 空行
~# grep -v ^$ /etc/rc.local
7、-c count 统计匹配到的行数
统计非空行的数量
~# grep -cv ^$ /etc/rc.local
7
统计空行的数量
~# grep -c ^$ /etc/rc.local
1
8、-r 递归检索
9、-l 一般与-r联用,只文显示包含关键字的件名,而不是显示文件内容
~# grep -rl "if" /script/
/script/adduser1.sh
/script/if7.sh
/script/for9.sh
/script/fuwu.sh
/script/if1.sh
10、-q quiet 静默输出 一般在写脚本时候用
~# grep -q root /etc/passwd
~# echo $?
0
11、-n 显示匹配行的行号
~# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
11:operator:x:11:0:operator:/root:/sbin/nologin
其他选项
-A
-B
-C
练习:
1、显示/etc/group文件中含有root的行
grep root /etc/group
2、显示/etc/passwd中以rp开头的行
grep ^rp /etc/passwd
3、显示/etc/group中不以:结尾的行
grep -v :$ /etc/group
4、显示/etc/rc.local的空行及其行号
grep -n ^$ /etc/rc.local
5、显示仅/mnt/cdrom目录下的文件类型为目录的文件(不使用find)
ll /mnt/cdrom | grep ^d
grep 支持的正则元字符
^ $ . * [] [^] \< \> \{\} \(\)
~# vim example1.txt
asdf
ad
bsd
nsd
a.d
5.6
b.c
bcc
aff
~# grep a.d example1.txt
asdf
a.d
~# grep "a\.d" example1.txt
a.d
~# grep a*d example1.txt
asdf
ad
bsd
nsd
a.d
练习:/etc/passwd文件
1、匹配第2个字符是a的行
~# grep --color ^.a /etc/passwd
2、查找出/usr/bin目录下具有suid权限的文件(不使用find)
~# ll /usr/bin/ | grep ^...[sS] --color
3、找出uid是两位数的行
[0-9][0-9]
~# grep --color x:[0-9][0-9]: /etc/passwd
~# grep --color :[0-9][0-9]:[0-9] /etc/passwd
4、显示passwd文件中含有两个bin的行
bin.*bin
~# grep --color "bin.*bin" /etc/passwd
~# grep --color "\<bin.*\<bin" /etc/passwd //仅仅是bin
bin:x:1:1:bin:/bin:/sbin/nologin
5、显示passwd文件中含有三个root的行
~# grep "\(root\).*\1.*\1" /etc/passwd --color
root:x:0:0:root:/root:/bin/bash
6、显示passwd文件中有9个连续的小写字母的行
[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]
[a-z]\{9\}
~# grep "[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]" /etc/passwd --color
~# grep "[a-z]\{9\}" /etc/passwd --color
~# vim e2.txt
aabbcc
aaabbbccc
aaaannnmms
@@@##$
@@##@@
$$@#$%
1、找出e2.txt文件中含有三个连续的相同字符的行
~# grep "\(.\)\1\1" e2.txt --color
aaabbbccc
aaaannnmms
@@@##$
POSIX表示法
Portable Operating System Interface —— 可移植操作系统接口
也是适用于非英文环境的系统,即适用于所有的语言环境
括号类 含义 匹配范围
[:space:] 包含换行符、空格、tab等所有空白字符
[:blank:] 空格和制表符 空格和tab
[:alpha:] 字母 a-zA-Z
[:alnum:] 字母和数字 a-Z0-9
[:cntrl:] 控制字符 ctrl、backspace等等
[:lower:] 小写字母 a-z
[:upper:] 大写字母 A-Z
[:digit:] 十进制数 0-9
[:xdigit:] 十六进制数 0-9a-fA-F
[:punct:] 标点符号 ,.?:‘ "
[^[:alpha:]] 取反,表示不是字母
~# grep "[[:space:]]\.[[:digit:]][[:space:]]" datafile --color
southwest SW Lewis Dalsass 2.7 .8 218
southeast SE Patricia Hemenway 4.0 .7 417
| 或者
? 表示0个或者1个它前面的字符 a?d ==> d ad
+ 表示1个或者多个它前面的字符 a+d ==> ad aad aaad ... ...
()
x{m}
x{m,}
x{m,n}
|
显示datafile文件中含有NW或者是WE的行
~# egrep "NW|WE" datafile --color
~# grep -E "NW|WE" datafile --color
?
~# egrep "2\.?[0-9]" datafile --color
+
~# egrep "a+" e2.txt --color
aabbcc
aaabbbccc
aaaannnmms
三.sed
sed 流编辑器 stream editor
是一种非交互式文本编辑器,默认是不会修改原文件的
工作原理
一行一行处理的
从文件的第一行开始读取,放到模式空间中进行相应处理,处理完将结果输出到屏幕上,然后继续读取下一行,直到所有的行都处理完毕,sed结束。
sed一般用于处理大文件。
语法:
sed [选项] ‘AddressCommand‘ 文件列表
1、常用的选项
-n:静默输出,关闭模式空间的输出,一般与p一起用
-e:允许进行多项编辑,也就是说对同一行做多次处理、也可以做多点编辑
-e ‘动作‘ -e ‘动作‘ 等价于 ‘动作1;动作2‘
-f sed脚本 : 指定运行的sed脚本的
-r:允许使用扩展正则
-i:直接修改原文件
2、Address : 定址、地址
1)单独的行号
如: 1 就表示要处理第一行
$ 表示最后一行
2)起始行,结束行
如: 1,5 处理第一行到第五行
3)/正则表达式/
如:/^root/ 处理以root开头的行
4)/正则表达式1/,/正则表达式2/ 最小匹配
表示处理从匹配到正则表达式1的行开始,到第一次匹配到正则表达式2之间的所有行
如果正则表达式1匹配到了,正则表达式2未匹配到,那么就从匹配到正则表达式1的行开始,一直处理到文件结束
如果正则表达式1未匹配到,那么就不对文件做处理。
如:/^bin/,/bash$/
binsdadaddaddass
dsfasidsfdhfj09bash
dasdasdasdf--bash
5)起始位置,+N 不是特别常用
表示从起始位置开始,后面的N行都处理
如:3,+5 处理3-8行
3、Command
常用的:d p s y q
其他的:a c i r w
h H g G
1)d:删除
~# sed ‘/UUID/d‘ /etc/fstab
~# sed ‘1,5d‘ /etc/fstab
~# sed ‘$d‘ /etc/fstab
~# sed ‘/tmp/,/sfs/d‘ /etc/fstab
~# sed ‘/UUID/,+5d‘ /etc/fstab
删除从第5行开始到最后一行的所有内容
~# sed ‘5,$d‘ /etc/passwd
2)p:打印
~# cat -n /etc/passwd | head > pass
~# sed ‘p‘ pass //每行会打印两遍,一遍是处理结果,一遍是模式空间的输出
~# sed -n ‘p‘ pass //只会打印一遍,因为模式空间的输出被关闭了
~# sed -n ‘3,5p‘ pass // 打印文件的3到5行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
~# sed -n ‘3p‘ pass
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
! 非
~# sed ‘3!d‘ pass //等价于打印第3行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
练习:
用sed分别实现head -1 和 tail -1的功能
head -1
~# sed -n ‘1p‘ pass
1 root:x:0:0:root:/root:/bin/bash
~# sed ‘1!d‘ pass
1 root:x:0:0:root:/root:/bin/bash
tail -1
~# sed -n ‘$p‘ pass
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
~# sed ‘$!d‘ pass
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
3)r 读取
~# sed ‘/^root/r /etc/issue‘ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
Red Hat Enterprise Linux Server release 6.4 (Santiago)
Kernel \r on an \m
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
4)w 写
~# sed ‘/root/w /tmp/douni‘ pass //将匹配到的行另存到文件中
~# cat /tmp/douni
1 root:x:0:0:root:/root:/bin/bash
5)a 追加 在匹配到的行的下一行插入内容
~# sed ‘/root/a hello root‘ pass | head -5
1 root:x:0:0:root:/root:/bin/bash
hello root
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
在文件的最后一行插入新内容
~# sed ‘$a The End‘ pass
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
The End
6)i 插入 在匹配行的上一行插入内容
~# sed ‘/daemon/i SO COOL‘ pass | head -5
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
SO COOL
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
~# sed ‘1i BEGINNING‘ pass | head -5 //在第一行插入内容
BEGINNING
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
7)c 修改 本行替换,将匹配到的行的内容替换成新内容
~# sed ‘/root/c ROOT‘ pass
1 ROOT
ROOT:x:0:0:root
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
~# sed ‘/IPADDR/c IPADDR=172.16.254.201‘ /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=no
BOOTPROTO=static
IPADDR=172.16.254.201
NETMASK=255.255.0.0
GATEWAY=172.16.254.1
8)y 转换的命令,对应替换
y///
y/123/ABC/
~# sed ‘y/1234/ABCF/‘ pass
A root:x:0:0:root:/root:/bin/bash
B bin:x:A:A:bin:/bin:/sbin/nologin
C daemon:x:B:B:daemon:/sbin:/sbin/nologin
F adm:x:C:F:adm:/var/adm:/sbin/nologin
5 lp:x:F:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:AB:mail:/var/spool/mail:/sbin/nologin
A0 uucp:x:A0:AF:uucp:/var/spool/uucp:/sbin/nologin
将文件中所有的小写字母转换成大写字母
~# sed ‘y/qwertyuiopasdfghjklzxcvbnm/QWERTYUIOPASDFGHJKLZXCVBNM/‘ pass
9)n next 处理匹配行的下一行,用的较少
~# sed -n ‘/root/p‘ pass
1 root:x:0:0:root:/root:/bin/bash
~# sed -n ‘/root/{n;p}‘ pass //{}里面写多个命令,之间用分号分隔
2 bin:x:1:1:bin:/bin:/sbin/nologin
10)q 退出 不再向模式空间读入新行
~# sed ‘/^bin/q‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
~# sed ‘1q‘ pass //head -1的又一种方法
1 root:x:0:0:root:/root:/bin/bash
练习:
1、将pass文件每行打印3次
~# sed ‘p;p‘ pass
2、打印passwd文件的第1行和第3行(多点编辑,用分号分隔命令)
~# sed -n ‘1p;3p‘ pass
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed -n -e ‘1p‘ -e ‘3p‘ pass
3、使用sed修改selinux的模式为permissive
~# sed ‘7c SELINUX=permissive‘ /etc/selinux/config
4、使用sed永久修改主机名为shell
~# sed ‘$c HOSTNAME=shell‘ /etc/sysconfig/network
3、删除pass文件的第1行和最后一行
~# sed ‘1d;$d‘ pass
以下操作datafile文件
4、在匹配到Lewis的行的下一行插入“has Lewis”
~# sed ‘/Lewis/a has Lewis‘ datafile
5、在文件的第一行插入“employee‘s information”
~# sed "1i employee‘s information" datafile
11)s 查找替换
定址s/模式匹配(旧的内容)/新的内容/[修饰符]
s@@@ s### s%%%
修饰符:
g:全局替换,一行中的多个
n:n为数字,1-512 替换第n个匹配到的内容
p:打印
w:另存为,写
~# sed ‘s/root/ROOT/‘ pass | head -3 //默认只替换第一次匹配到的
1 ROOT:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed ‘s/root/ROOT/2‘ pass | head -3 //替换每行中第2个匹配到的
1 root:x:0:0:ROOT:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed ‘s/root/ROOT/g‘ pass | head -3 //全部替换
1 ROOT:x:0:0:ROOT:/ROOT:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
练习:
1、从以root开头,到以login结尾的行,将sbin替换成bin (/etc/passwd)
~# sed ‘/^root/,/login$/s/sbin/bin/‘ /etc/passwd | head
2、将格式为2015/09/02的日期,替换为2015; 09; 02的格式(注意分号后面有空格)
~# date "+%Y/%m/%d"
2015/09/02
~# date "+%Y/%m/%d" | sed ‘s#/#; #g‘
2015; 09; 02
~# date "+%Y/%m/%d" | sed ‘s/\//; /g‘
3、将selinux配置文件中的disabled替换为enforcing,暂时不作用于原文件
~# sed ‘/SELINUX/s/disabled/enforcing/‘ /etc/selinux/config
思考题:删除文件中所有的数字 **** //一种思想,用替换去删除字符等
~# sed ‘s/[0-9]//g‘ pass
-i:直接作用于文件
~# sed ‘s/static/dhcp/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
~# sed -i ‘s/static/dhcp/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
~# sed -i.bak ‘s/dhcp/static/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
//.bak是备份文件的后缀名
~# ls /etc/sysconfig/network-scripts/ifcfg-eth0*
ifcfg-eth0 ifcfg-eth0.bak
模式匹配时的特殊符号
^:每行的开头
给全文加注释
~# sed ‘s/^/#/‘ pass
在第8到10行的开头每行加上###
~# sed ‘s/^/###/‘ pass
$:每行的结尾
在匹配到root的行的末尾添加###
~# sed ‘/root/s/$/###/‘ pass
1 root:x:0:0:root:/root:/bin/bash###
-r选项: 支持扩展正则
~# sed -r ‘s/[[:space:]]+//‘ pass
~# sed ‘s/[[:space:]]*//‘ pass
1、将history命令执行结果中编号前面的空白字符删掉
~# history | sed -r ‘s/[[:space:]]+//‘
2、删除文件中的空行和空白行
~# cat txt
adadadadada dasdasdadas
dadada
gdfgdgdfgfdg
~# cat -A txt
adadadadada dasdasdadas$
$
$
dadada $
^I^I $
gdfgdgdfgfdg$
~# sed -r ‘/^$/d;/^[[:space:]]+$/d‘ txt
adadadadada dasdasdadas
dadada
gdfgdgdfgfdg
& 引用 用来代替匹配到的模式的
将每一行的行号加上括号
~# sed -r ‘s/[0-9]+/(&)/‘ pass
~# vim test
hello, i like you
hi, my love
like ==> liker
love ==> lover
~# sed ‘s/l..e/l..er/‘ test
hello, i liker you
hi, my lover
~# sed -r ‘s/(l..e)/\1r/‘ test
hello, i liker you
hi, my lover
like ==> Like
love ==> Love
~# sed -r ‘s/l(..e)/L\1/‘ test
hello, i Like you
hi, my Love
练习:
1、删除每行的第一个字符
2、删除每行的第二个字符
3、删除每行的倒数第一个字符
4、删除每行的倒数第二个字符
5、交换每行的第一个和第二个字符
思考:
删除/etc/passwd每行的第一个字段
交换/etc/passwd文件的第一个和第二个字段
作业:
1、将/etc/inittab文件中的id:5:initdefault中的5替换成3
以下使用datafile3
1、将Jon的名字改为Jonathan
2、删除文件的前3行
3、打印文件的第5到10行
4、删除含有Lane的行
5、打印生日在11月和12月的行
6、在以Fred开头的行末尾添加三个*
7、将所有包含Jose的行替换为Match Jose
8、把Popeye的生日改为11/14/46,前提:需要你先匹配出生日
9、删除所有的行
10、将文件中的所有大写字母用括号()括起来
每多少行操作一次
first~step
first:起始行号
step:步长
打印偶数行
~# sed -n ‘2~2p‘ pass
2 bin:x:1:1:bin:/bin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
8 halt:x:7:0:halt:/sbin:/sbin/halt
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
每3行打印一次
~# sed -n ‘1~3p‘ pass
1 root:x:0:0:root:/root:/bin/bash
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
=:打印当前行号
统计文件的行数
~# sed -n ‘$=‘ /etc/passwd
76
~# vim sc1.sed
/Lewis/a \
hello everyone \
ni hao
/Suan/c has suan
1i \
************** \
begin \
**************
$d
调用脚本
~# sed -f sc1.sed datafile
**************
begin
**************
northwest NW Charles Main 3.0 .98 334
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 218
hello everyone
ni hao
has suan
southeast SE Patricia Hemenway 4.0 .7 417
eastern EA TB Savage 4.4 .84 520
northeast NE AM Main Jr. 5.1 .94 313
western WE Sharon Gray 5.3 .97 5 23
north NO Margot Weber 4.5 .89 59
模式空间
用于处理文本行的
PATT,最多能够存储8192字节
保留空间
用于保留文本行的
HOLD,sed用来保存已经处理过的文本行的,最多保存8192字节,默认有一个空行
涉及到的命令
h:将模式空间的内容复制到保留空间 —— 覆盖模式
H:将模式空间的内容追加到保留空间 —— 追加模式
g:将保留空间的内容复制到模式空间 —— 覆盖模式
G:将保留空间的内容追加到模式空间 —— 追加模式
x:将模式空间的内容和保留空间的内容进行交换
交换第一行和第二行的内容
~# sed ‘1{h;d};2G‘ pass | head -5
2 bin:x:1:1:bin:/bin:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
将第1行到第3行的内容复制到第4行后面
~# sed ‘1h;2,3H;4G‘ pass | head
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
将第1行到第3行的内容剪切到第4行的后面
~# sed ‘1{h;d};2,3{H;d};4G‘ pass
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
在每行的下面添加一个空行
~# sed ‘G‘ pass
思考:倒序输出文件的每一行
假设文件如下:
aa
bb
cc
dd
要求输出结果如下:
dd
cc
bb
aa
四.awk
awk 一种编程语言、文本编辑器、也是一种非交互式的编辑器
功能:对文本数据进行汇总和处理,是一个报告的生成器,能够对数据进行排版
awk nawk gawk posix awk
nawk —— solaris
gawk,awk —— GNU Linux
工作过程
将文件中的内容逐行的进行扫描,把整行内容存入内置变量$0中;
再按照指定的分隔符(默认的分隔符是空白)将输入行切成若干个列(字段),存入变量$1~$100,再使用命令(print、printf)将变量打印输出,输出分隔符默认也是空白
再读取下一行,循环处理,直到文件处理结束。
~# ifconfig eth0 | grep Bcast | awk ‘{print $2}‘ | awk -F: ‘{print $2}‘
172.16.254.200
~# df -h / | tail -1 | awk ‘{print $5}‘ | cut -d"%" -f1
18
1、awk的语法
awk [选项] ‘/模式匹配(定址)/{处理动作1;处理动作2;... ...; 处理动作n}‘ 文件列表
2、简单操作
~# head /etc/passwd > pass
打印pass文件中的用户名和uid
~# awk -F: ‘{print $1,$3}‘ pass
-F:指定输入文件字段分隔符
3、语法中的说明
1)设定输入分隔符 -F
分隔符可以是数字、字母、符号和空白
可以同时指定多个分隔符 : / ,
默认是空白
---- 单个符号的分隔符
-F:
---- 复合分隔符,多个字符组成一个分隔符
:/
pass文件以:/为分隔符,打印第一个字段
~# awk -F":/" ‘{print $1}‘ pass
---- 同时指定多个分隔符
:和/都是分隔符
~# awk -F"[:/]" ‘{print $1,$10}‘ pass
---- 以空为分隔符
~# awk -F "" ‘{print $1,$2}‘ pass //注意:-F后面有空格
2)awk输出
(1)print
打印内容的,内容可以是文件中的内容,也可以跟文件内容毫无关系
~# awk ‘{print "hello"}‘ pass //打印内容和文件不相关,只是借用了pass文件的行,有多少行内容,hello就会被打印多少次
打印每一行的内容
~# awk ‘{print $0}‘ pass
~# awk ‘{print}‘ pass
\n :换行符
~# head -1 pass | awk ‘{print "hello\nworld"}‘
hello
world
\t : 制表符
~# head -1 pass | awk ‘{print "hello\tworld"}‘
hello world
~# awk -F: ‘{print $1"\t"$3}‘ pass
print要点:
a、各个输出字段之间用逗号分隔,而输出的时候默认是以空白为分隔符的
b、print后面如果不跟字段,那么默认打印整行
c、print输出时默认是有换行的
1、在每行的下面打印一个空行
~# awk ‘{print $0"\n"}‘ pass
2、使用awk取出eth0网卡的IP地址
~# ifconfig eth0 | awk ‘/Bcast/{print $2}‘ | cut -d: -f2
172.16.254.200
(2)printf —— 可以格式化输出的,默认没有换行
使用格式
printf format,item1,item2,... ...,itemn
format的指示符都是以%开头的,后面跟一个字符,如:
%s:表示是字符串
%d:表示十进制数
%f: 表示浮点数,其实就是小数 float
%%:表示%本身
%x:表示十六进制数
%o:表示八进制数
%c:表示字符
修饰符: N(数字) 表示显示宽度 %10s
- 表示左对齐,默认是右对齐 %-10s
对于浮点数:
%5.2f : 其中5表示总的显示宽度(整数位+小数位),2表示小数位的位数
%-5.2f
%.2f :表示整数位全部保留,小数位保留两位
~# awk -F : ‘{printf "%10s%5d",$1,$3}‘ pass //默认printf是没有换行的
root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 uucp 10~#
~# awk -F : ‘{printf "%10s%5d\n",$1,$3}‘ pass
~# awk -F : ‘{printf "%-10s%5d\n",$1,$3}‘ pass
%d直接取整,不进行四舍五入;%f进行四舍五入的
~# echo "12.64 23.456 11.2345" > test
~# awk ‘{printf "%d\n",$1}‘ test
12
~# awk ‘{printf "%.2f\n",$2}‘ test
23.46
printf要点:
a、与print不同的是,printf需要指定格式
b、格式其实是用来指定后面每个条目的输出格式的
c、printf默认不会自动打印换行符的,有需要时候手动指定"\n"
d、默认没有输出分隔符
~# awk ‘{printf "%d%d\n",$1,$2}‘ test
1223
~# awk ‘{printf "%d %d\n",$1,$2}‘ test
12 23
练习:
格式化输出passwd文件中的用户名,UID,shell三列
~# awk -F: ‘{printf "%-15s%-6d%-15s\n",$1,$3,$7}‘ /etc/passwd
3)awk的操作符
(1)算数运算符
-x:表示负数 +x(x):表示正数
x+y x-y x*y x/y x%y x**y 等价于 x^y(x的y次幂)
~# awk ‘{print $3+$5}‘ employees
547778
34111
651654
338183
~# awk ‘{print $3+$5,$3-$5,$3*$5,$5/$3,$5%$3}‘ employees
547778 -538930 2403798096 122.82 3626
34111 -23419 153777690 5.38066 2035
651654 -648346 1075100000 392.987 1632
338183 -334817 566329500 199.941 1583
~# echo hello | awk ‘{print 2^16}‘
65536
~# awk ‘{printf "%-10d\n",$5+$3}‘ employees
547778
34111
651654
338183
(2)关系运算符
a、数值之间的关系运算符
> < >= <= == !=
打印uid小于等于10 的行
~# awk -F: ‘$3<=10{print $0}‘ /etc/passwd
~# awk -F: ‘$3<=10{print}‘ /etc/passwd
~# awk -F: ‘$3<=10‘ /etc/passwd
b、字符串之间的关系运算符
== !=
$1=="root"
$1!="root"
~# awk -F: ‘$1=="root"‘ pass
root:x:0:0:root:/root:/bin/bash
x ~ /y/ —— 匹配正则 其中y可以是正则表达式
打印用户名中含有o的用户的名字
~# awk -F: ‘$1 ~ /o/{print $1}‘ pass
root
daemon
shutdown
x !~ /y/ —— 不匹配正则
~# awk -F: ‘$1 !~ /o/{print $1}‘ pass
bin
adm
lp
sync
halt
mail
uucp
练习:
1、打印/etc/fstab中含有boot的行
~# awk ‘/boot/‘ /etc/fstab
~# awk ‘$0 ~ /boot/‘ /etc/fstab
2、打印/etc/passwd文件中的uid为10的用户的用户名、uid及家目录
~# awk -F: ‘$3==10{print $1,$3,$6}‘ /etc/passwd
uucp 10 /var/spool/uucp
3、打印用户shell为登录shell的用户名及shell
~# awk -F: ‘$7 ~ /sh$/{print $1,$7}‘ pass
root /bin/bash
(3)逻辑运算符
&& || !
打印uid在5到10之间的用户的用户名,UID
~# awk -F: ‘$3>=5 && $3<=10{print $1,$3}‘ /etc/passwd
sync 5
shutdown 6
halt 7
mail 8
uucp 10
打印uid大于10或者uid小于5的用户名
~# awk -F: ‘$3<5 || $3>10{print $1,$3}‘ /etc/passwd
打印uid不大于3的用户名
~# awk -F: ‘!($3>3){print $1,$3}‘ pass
(4)赋值运算符
= += -= *= /= %= **= ^=
++ --
sum+=$3
练习:
1、打印uid和gid不相同的用户的用户名、uid、gid
~# awk -F: ‘$3!=$4{print $1,$3,$4}‘ /etc/passwd
2、交换pass文件的第一个字段和第二个字段
~# awk -F: ‘{print $2":"$1":"$3":"$4":"$5":"$6":"$7}‘ pass
3、打印100以内能够被7整除,以及包含7 的数
~# seq 100 | awk ‘$0%7==0 || $0 ~ /7/‘
~# seq 100 | awk ‘$0%7==0 || /7/‘
4、awk的模式匹配(即定址) —— awk + 正则表达式
常见的模式
1)空模式:也就是每一行都要做处理的模式
~# awk -F: ‘{print $1}‘ pass
2)正则表达式
a、固定定址
~# awk -F: ‘/^ro/{print $1}‘ pass
root
b、范围定址
~# awk -F: ‘/^ro/,/^lp/{print $1}‘ pass
root
bin
daemon
adm
lp
注意:awk是不支持行号定址的
反例:
~# awk -F: ‘2{print $1}‘ pass
3)表达式
$3>=5
$7 ~ /sh$/
4)特殊模式
BEGIN {}
END {}
5)NR变量定址
NR>1 //行号大于1的行
5、awk的变量
种类:内置变量、自定义的变量
1)内置变量
(1)$0 表示一整行的内容
(2)$1 ~ $100
$1:第一列
(3)与记录相关的变量(记录就是行)
FS(field separator):字段分隔符,默认是空白
FS=":"
OFS(Output):输出字段分隔符
RS(record):记录的分隔符,即行的分隔符
ORS:输出记录分隔符
(4)与数据相关的变量
NR(Number of Record):记录数,awk的处理的行的总数 NR在很多情况下可以看成行号
NF(Number of Field):当前行的字段数
$NF:当前行的最后一个字段的值
$(NF-1):当前行的倒数第二个字段
~# cat employees
Tom Tom 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
Tom Tom 4424 5/12/66
~# awk ‘{print NR":"NF":"$NF}‘ employees
1:5:543354
2:5:28765
3:5:650000
4:5:336500
5:4:5/12/66
打印pass文件的第2行
~# awk ‘NR==2‘ pass
bin:x:1:1:bin:/bin:/sbin/nologin
2)自定义变量
命名:由字母、数字、下划线组成,不能以数字开头,不能使用关键字,最好见名知意
变量名区分大小写
变量可以先定义再使用,也可以直接使用
给变量赋值
变量名=数值
a=5
变量名="字符串" //注意:此处一定有引号
username="root"
~# echo hello | awk ‘{num=5;pass="douniwan";print num,pass}‘
5 douniwan
练习:
1、打印passwd文件的奇数行的行号和内容
NR%2==1 或者 NR%2!=0
2、打印每行的倒数第三个字段(employees文件)
$(NF-2)
3、从第一行开始,每3行打印一次(即打印行号为1 4 7... 这样的行)
NR%3==1
4、输出以 : 和 / 为分隔符的情况下,passwd文件的最后一列
-F"[:/]" $NF
5、打印/etc/passwd文件的偶数行
NR%2==0
6、打印pass文件中没有指定shell的用户名(文件自己处理一下,可以将某个或者某几个的shell删除掉)
-F: $7 == ""
$7 ~ /^$/
7、打印passwd文件的第3行和第5行
NR==3 || NR==5
sed相关练习
1、将passwd文件 中的第20行到第30行的内容复制到第33行后面,同时显示行号(可以使用除了sed以外的命令)
cat -n passwd | sed ‘20h;21,30H;33G‘
2、写sed脚本 处理文件为datafile3
1)在第一行插入标题:EMPLOYEES
2)删除以500为结尾的行的工资项(注意:不是删除行,只是删除工资那个段)
3)将名和姓的位置颠倒输出
4)在文件末尾添加OVER
1i EMPLOYEES
s/:[0-9]*500$/:/
s/^([A-Z][a-z]*) ([A-Z][a-z]*)/\2 \1/
$a OVER
sed -rf script.sed datafile3
--------------------------------------------------------------------------------------
6、赋值运算
a+=$2 等价于 a=a+$2
a+=5
-= *= /= %= ^=
a++ ++a
a-- --a
~# echo hello | awk ‘{a=5;b=a++;print a,b}‘
6 5
~# echo hello | awk ‘{a=5;b=++a;print a,b}‘
6 6
练习:
1)把employees里面最后一个字段的值减去8,打印
~# awk ‘{print $NF-8}‘ employees
543346
28757
649992
336492
2)将employees倒数第三列对3取余并打印
~# awk ‘{print $(NF-2)%3}‘ employees
2
0
1
0
0
~# awk ‘{a=$(NF-2)%3;print a}‘ employees
2
0
1
0
0
7、awk的特殊模式
awk的完整语法
awk [选项] ‘BEGIN{动作}定址{动作}END{动作}‘ 文件列表
BEGIN{} : 在读取文件之前就执行,只执行一次;一般用于初始化分隔符、初始化变量、定义数组、打印表头等
定址{} : 这一部分可能会执行多次
END{} : 在处理完文本之后执行,只执行一次;一般用于汇总数据 比如:打印总成绩、平均成绩等等
~# awk ‘BEGIN{FS=":";print "username"}/root/{print $1}END{print "over"}‘ /etc/passwd
username
root
operator
over
说明:
BEGIN和END可以单独存在的
1)只有BEGIN,后面不需要加文件
~# awk ‘BEGIN{print "hello"}‘
hello
2)只有END,后面必须加文件,文件可以是空文件,也可以是有内容的文件
~# awk ‘END{print "end"}‘ pass
end
~# touch haha
~# awk ‘END{print "end"}‘ haha
end
3)没有BEGIN,也没有END
~# awk ‘{sum=0;sum+=$3;print $1,$3,sum}‘ employees
Tom 4424 4424
Mary 5346 5346
Sally 1654 1654
Billy 1683 1683
Tom 4424 4424
4)有BEGIN,没有END‘
~# awk ‘BEGIN{sum=0}{sum+=$3;print $1,$3,sum}‘ employees
Tom 4424 4424
Mary 5346 9770
Sally 1654 11424
Billy 1683 13107
Tom 4424 17531
5)既有BEGIN,又有END
~# awk ‘BEGIN{sum=0}{sum+=$3;print $1,$3}END{print "total:"sum}‘ employees
Tom 4424
Mary 5346
Sally 1654
Billy 1683
Tom 4424
total:17531
练习:
统计/etc目录下所有的普通文件的总大小
~# ll /etc | awk ‘BEGIN{sum=0}/^-/{sum+=$5}END{print sum}‘
1257642
8、awk的脚本
BEGIN{
命令
}
定址{
命令
}
END{
命令
}
打印ule总成绩,平均成绩
~# vim sc.awk
BEGIN{
print "This is ule score table"
}
NR>1{
ule+=$2
}
END{
print "ule‘s total score is :"ule
print "ule‘s average score is :"ule/(NR-1)
}
~# awk -f sc.awk score
This is ule score table
ule‘s total score is :246
ule‘s average score is :61.5
练习:
1、求得ULA的总成绩,平均成绩;求oracle的总成绩,平均成绩
2、样例文件staff.txt
文件内容如下:
~# cat staff.txt
id name sal date
100 tom 10000 2013/10/1
101 jerry 8000 2013/10/10
102 john 5000 2013/11/1
103 mark 6000 2013/12/10
104 rose 2000 2014/01/01
105 jake 1500 2014/01/10
1)统计每个月发出去的总工资
~# awk ‘NR>1{sal+=$3}END{print sal}‘ staff.txt
32500
NR>1{
sal+=$3
}
END{
print sal
}
2)统计2013年入职的人数
~# awk ‘/2013/{count++}END{print count}‘ staff.txt
4
3)统计工资超过5000的有几个人
~# awk ‘$3>5000 && NR>1 {count++}END{print count}‘ staff.txt
3
1、awk与重定向
passwd
将uid>100的用户名及uid保存到/tmp/uidup100文件中
~# awk -F: ‘$3 > 100{print $1,$3 > "/tmp/uidup100"}‘ /etc/passwd
输入重定向 getline
getline 接收来自于标准输入、管道和文件(非当前处理文件)的数据,存入到一个变量中,再给awk使用
~# awk ‘BEGIN{"date" | getline a}{print $0}END{print a}‘ pass
~# tty
/dev/pts/10
从标准输入读取一个数据,传给变量username,判断passwd文件中是否有这样的用户名,如果有,打印行号和用户名
~# vim sc2.awk
BEGIN{
FS=":"
printf "请输入一个用户名: "
getline username < "/dev/pts/10"
}
{
if($1==username) 判断
{
print NR,$1
}
}
~# awk -f sc2.awk /etc/passwd
请输入一个用户名: root
1 root
2、awk与管道
~# awk -F: ‘$3 > 100{print $1,$3 | "sort -nr -k2"}‘ /etc/passwd
3、使用awk执行系统命令
~# awk ‘BEGIN{print "today is ";system("date")}‘
today is
Mon Sep 7 12:26:03 CST 2015
基本的结构
1、顺序结构
2、分支判断 if
3、循环结构 while for 循环控制语句:break continue exit next
一、三元操作符
?:
判断条件?输出结果1:输出结果2
如果条件为真,输出问号后面的结果,否则输出冒号后面的结果
~# awk -F: ‘{print $1":"($3>$4?"uid:"$3:"gid:"$4)}‘ pass
二、分支判断结构 if
1、语法格式:
if(条件表达式) —— 注意:如果if是写在awk的脚本中,那么他的整体都要写在{}中,因为它属于动作
{
动作
}
else
{
动作
}
修改三元操作符的小练习
~# vim if1.awk
BEGIN{
FS=":"
}
{
if($3>$4)
{
print $1":uid:"$3
}
else
{
print $1":gid:"$4
}
}
~# awk -f if1.awk pass
2、多分支判断语法结构
if(条件表达式)
{
动作
}
else if(条件表达式)
{
动作
}
... ...
else
{
动作
}
~# cat if2.awk
#!/usr/bin/awk -f //shabang,指定文件中的命令的解析环境是awk
NR>1{
if($2>=90)
{
print $1": A"
}
else if($2>=80)
{
print $1": B"
}
else
{
print $1": C"
}
}
~# chmod +x if2.awk
~# ./if2.awk score
mike: B
rose: C
john: A
larry: C
练习:
统计ula成绩在以下每个分数段的人数
>=90
>=80
>=70
打印效果:
成绩在90分以上的有__人
成绩在80分到90分之间的有__人
成绩在70分到80分之间的有__人
~# cat if3.awk
#!/usr/bin/awk -f
NR>1{
if($3>=90)
{
up90++
}
else if ($3>=80)
{
up80++
}
else if($3>=70)
{
up70++
}
}
END{
printf "成绩在90分以上的有%d人\n",up90
printf "成绩在80分到90分之间的有%d人\n",up80
printf "成绩在70分到80分之间的有%d人\n",up70
}
~# chmod +x if3.awk ^C
~# ./if3.awk score
成绩在90分以上的有1人
成绩在80分到90分之间的有1人
成绩在70分到80分之间的有1人
三、循环
功能:
1)从行中取出每个字段,循环字段的
2)遍历数组元素
1、while循环
语法:
变量初始值
while (条件)
{
动作
变量的更新
}
mike
85
80
90
~# vim while1.awk
/mike/{
i=1
while(i<=NF)
{
print $i
i++
}
}
~# awk -f while1.awk score
mike
85
80
90
练习:
1)将passwd文件的第一行的每个字段纵向打印
输出结果如下:
root
x
0
0
root
/root
/bin/bash
~# cat while2.awk
BEGIN{
FS=":"
}
NR==1{
i=1
while(i<=NF)
{
print $i
i++
}
}
2)倒序输出passwd文件的每一列
结果例如(以一行为例)
/bin/bash:/root:root:0:0:x:root
法一:
~# awk ‘BEGIN{FS=":";OFS=":"}{print $7,$6,$5,$4,$3,$2,$1}‘ pass
法二:
~# cat while4.awk
BEGIN{
FS=":"
}
{
i=NF
while(i>1)
{
printf $i":"
i--
}
print $1
}
2、for循环
语法:
for(变量初始值;判断条件;变量的更新)
{
动作
}
~# vim for1.awk
/mike/{
for(i=1;i<=NF;i++)
{
print $i
}
}
四、判断加循环
~# awk ‘NR>1{print $2,$3,$4}‘ score > number
例子:
输出每行的最大值
~# vim if-for.awk
{
max=$1
for (i=1;i<=NF;i++)
{
if($i>max)
{
max=$i
}
}
print max
}
~# awk -f if-for.awk number
90
70
91
100
五、双重循环 (嵌套循环)
打印99乘法口诀表
~# vim for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
printf j"*"i"="i*j"\t"
}
printf "\n"
}
}
~# awk -f for-for.awk
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
六、循环控制语句
continue 跳出本次循环
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {continue}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
break 跳出当前循环
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {break}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
exit 退出脚本
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {exit}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
next 跳过本行,读取下一行
~# awk ‘/name/{next};{print $0}‘ score
数组: array
数组是使用一个变量名 来保存一组数据,通常这些数据的类型是一样的
数组中的数据(元素) 是与数组下标一一对应的
如果想要取出数组中的某个元素,就会使用到数组名和下标
awk中的数组也成为关联数组,是因为它的下标可以是数值,也可以是字符串
一、数组的定义
数组名[下标]=值
二、数组的遍历
for循环遍历数组
语法:
1)for (i=0;i<NR;i++)
2) for (下标 in 数组名) {print 数组名[下标]}
定义数组及给数组中元素赋值
~# vim arr.awk
BEGIN{
a[1]="aa"
a[2]="bb"
a[3]="cc"
for(i=1;i<=3;i++)
{
print a[i]
}
}
~# awk -f arr.awk
aa
bb
cc
awk支持的下标的类型
1)使用数字或变量作为下标
name[1] name[x++] name[NR]
~# awk ‘{name[x++]=$1}END{for(i=0;i<NR;i++){print i,name[i]}}‘ employees
0 Tom
1 Mary
2 Sally
3 Billy
4 Tom
2)使用字符串做下标
name["tom"]++
~# vim datafile4
cat
dog
pig
cat
dog
dog
bird
dog
rabbit
统计文件中每种动物有几只?
~# awk ‘{count[$1]++}END{for(i in count){print i,count[i]}}‘ datafile4
cat 2
bird 1
rabbit 1
dog 4
pig 1
统计apache日志中每个IP的访问次数,显示访问次数最多的五个IP及访问次数
统计/root/.bash_history文件中执行次数最多的十条命令
统计系统中使用每种shell的有几个人?
统计服务器上tcp连接情况(每种监听状态有几个?)
如:
LISTEN 10
ESTABLISHED 30
~# netstat -ant
内置函数
自定义函数
一、内置函数
man awk //搜索Function
1、sub(正则表达式,替换字符串) —— 查找并替换
~# awk ‘{sub(/NW/,"NorthWest");print}‘ datafile
northwest NorthWest Charles Main 3.0 .98 3 34
2、tolower(字符串) —— 转换成小写
toupper(字符串) —— 转换成大写
~# awk ‘{print toupper($1)}‘ datafile
~# awk ‘{print tolower($2)}‘ datafile
3、index(原字符串,子串) —— 输出子串在原字符串中的位置
~# awk ‘{print index($1,"o"),$1}‘ datafile
2 northwest
0 western
2 southwest
2 southern
2 southeast
0 eastern
2 northeast
0 western
2 north
0 central
4、length(字符串) —— 显示字符串的长度
~# awk ‘{print length($1),$1}‘ datafile
9 northwest
7 western
9 southwest
8 southern
9 southeast
7 eastern
9 northeast
7 western
5 north
7 central
二、自定义函数
格式
function 函数名(参数1,参数2,... ... ,参数n) {
函数体
return value //返回值
} //参数也是可有可无的
~# awk ‘function hello(){print "shell is over"}{hello()}‘ pass
正则表达式 RE 、 Regular Expression
是一种字符模式,是在匹配文本时,使用一些特殊符号,匹配到用户想要的东西
字符模式:
普通字符:没有任何特殊含义的字符
元字符:具有特殊含义的字符 ^ $ * . [] () {}
正则表达式一般是夹在双斜线之间的 如:/^abc/等
介绍正则表达式元字符
元字符 功能 例子 匹配结果
^ 行首定位符 /^root/ 匹配以root开头的行
$ 行尾定位符 /sh$/ 匹配以sh结尾的行
. 匹配任意单个字符(除了换行符) /l.ve/ 匹配live、love、... ...
* 前导符
匹配0个或者多个它前面的模式 /l*ve/ 匹配ve、lve、llve、... ...
.* 匹配0到多个任意字符
[] 匹配一组字符中的任意一个 /l[ioIO]ve/ 匹配live、love、lIve、lOve
[x-y] 匹配一段范围中的任意一个 /l[o-z]ve/ 匹配love、lpve、lqve、... ...、lzve
[0-9] 数字
[a-z] 小写字母
[A-Z] 大写字母
[a-z0-9] 小写字母或数字
[-+*/] +-*/ 四则运算
[a-Z] 字母
[^] 表示取反 /^[^abc]ve/ 匹配除了ave、bve、cve以外的三个字符的字符串
[^0-9] 不是数字
\ 用于转义元字符的 /93\.4/ 匹配93.4
\< 词首定位符 /\<bin/ 匹配bin、binary、... ...
\> 词尾定位符 /sh\>/ 匹配bash、csh、ksh、... ...
rootfs
模式的重复{}
x\{m\} x是字符或者字符串,m是数字,表示次数
匹配x出现m次 /a\{3\}/ 匹配到aaa
x\{m,\} 匹配x出现至少m次 /a\{3,\}/ 匹配aaa、aaaa、aaaaaaaa、aaaaaaa、... ...
x\{m,n\} 匹配x出现m次到n次 /a\{3,5\}/ 匹配aaa、aaaa、aaaaa
(root)
(a+(b-c)*d)
\(...\) 分组、标签
& \1 \2
/\(love\)/ \1r
\(root\).*\(bin\).*\2\1 \1ly
a and b
\(a\) and \(b\) ==> \2 and \1
二.正则表达式用法
(一).vim与正则表达式
1、查找替换(letter) tom换成mary
~# vim letter
:%s/\<[Tt]om\>/mary/ ——> tom Tom
2、行首行尾 picnic
/^love
/love$
3、任意字符 picnic
/l.ve
4、前导符 picnic
/o*v
5、范围 picnic
/love[a-z]
6、取反 picnic
/love[^a-z]
7、综合 invite
/^[A-Z]..$ 匹配Dan这一行
/^[A-Z][a-z]*.*3[0-5] 匹配到There are around 30 to 35
//由此可以看出,正则表达式执行的是最大匹配
8、标签
:%s/\(Ginger\) and \(Larry\)/\2 and \1/
:%s/\(Ginger\)\(.*\)\(Larry\)/\3\2\1/
s@@@ s### s%%% s/// 等价的
(二).grep与正则表达式
GREP —— Global Regular Expression Print
好处:非交互
不影响原文件内容,目的就是过滤出用户感兴趣的内容
命令格式
grep [选项] "正则表达式" 文件列表
grep执行状态返回值三种
0:该文件中搜索到了匹配行
1:该文件中未搜索到匹配行
2: 搜索的文件不存在
~# grep "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
~# echo $?
0
~# grep "roooot" /etc/passwd
~# echo $?
1
~# grep "root" /etc/passwd1
grep: /etc/passwd1: No such file or directory
~# echo $?
2
grep基本使用
设定别名
#alias grep=‘grep --color=auto‘
# vim /etc/bashrc
1、--color 带颜色显示匹配到的关键字
~# grep --color "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
2、-i 忽略大小写
~# cat pass
Root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
~# grep "root" pass --color
Root:x:0:0:root:/root:/bin/bash
~# grep -i "root" pass --color
Root:x:0:0:root:/root:/bin/bash
3、-v 取反
~# grep -v "nologin" /etc/passwd //打印不包含nologin的行
4、^
打印/root/.bashrc文件中的注释行
~# grep ^# /root/.bashrc
打印/etc/inittab文件中的非注释行
~# grep -v ^# /etc/inittab
id:5:initdefault:
5、$
显示passwd文件中以bash结尾的行
~# grep bash$ /etc/passwd
6、^$ 空行
~# grep -v ^$ /etc/rc.local
7、-c count 统计匹配到的行数
统计非空行的数量
~# grep -cv ^$ /etc/rc.local
7
统计空行的数量
~# grep -c ^$ /etc/rc.local
1
8、-r 递归检索
9、-l 一般与-r联用,只文显示包含关键字的件名,而不是显示文件内容
~# grep -rl "if" /script/
/script/adduser1.sh
/script/if7.sh
/script/for9.sh
/script/fuwu.sh
/script/if1.sh
10、-q quiet 静默输出 一般在写脚本时候用
~# grep -q root /etc/passwd
~# echo $?
0
11、-n 显示匹配行的行号
~# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
11:operator:x:11:0:operator:/root:/sbin/nologin
其他选项
-A
-B
-C
练习:
1、显示/etc/group文件中含有root的行
grep root /etc/group
2、显示/etc/passwd中以rp开头的行
grep ^rp /etc/passwd
3、显示/etc/group中不以:结尾的行
grep -v :$ /etc/group
4、显示/etc/rc.local的空行及其行号
grep -n ^$ /etc/rc.local
5、显示仅/mnt/cdrom目录下的文件类型为目录的文件(不使用find)
ll /mnt/cdrom | grep ^d
grep 支持的正则元字符
^ $ . * [] [^] \< \> \{\} \(\)
~# vim example1.txt
asdf
ad
bsd
nsd
a.d
5.6
b.c
bcc
aff
~# grep a.d example1.txt
asdf
a.d
~# grep "a\.d" example1.txt
a.d
~# grep a*d example1.txt
asdf
ad
bsd
nsd
a.d
练习:/etc/passwd文件
1、匹配第2个字符是a的行
~# grep --color ^.a /etc/passwd
2、查找出/usr/bin目录下具有suid权限的文件(不使用find)
~# ll /usr/bin/ | grep ^...[sS] --color
3、找出uid是两位数的行
[0-9][0-9]
~# grep --color x:[0-9][0-9]: /etc/passwd
~# grep --color :[0-9][0-9]:[0-9] /etc/passwd
4、显示passwd文件中含有两个bin的行
bin.*bin
~# grep --color "bin.*bin" /etc/passwd
~# grep --color "\<bin.*\<bin" /etc/passwd //仅仅是bin
bin:x:1:1:bin:/bin:/sbin/nologin
5、显示passwd文件中含有三个root的行
~# grep "\(root\).*\1.*\1" /etc/passwd --color
root:x:0:0:root:/root:/bin/bash
6、显示passwd文件中有9个连续的小写字母的行
[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]
[a-z]\{9\}
~# grep "[a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z][a-z]" /etc/passwd --color
~# grep "[a-z]\{9\}" /etc/passwd --color
~# vim e2.txt
aabbcc
aaabbbccc
aaaannnmms
@@@##$
@@##@@
$$@#$%
1、找出e2.txt文件中含有三个连续的相同字符的行
~# grep "\(.\)\1\1" e2.txt --color
aaabbbccc
aaaannnmms
@@@##$
POSIX表示法
Portable Operating System Interface —— 可移植操作系统接口
也是适用于非英文环境的系统,即适用于所有的语言环境
括号类 含义 匹配范围
[:space:] 包含换行符、空格、tab等所有空白字符
[:blank:] 空格和制表符 空格和tab
[:alpha:] 字母 a-zA-Z
[:alnum:] 字母和数字 a-Z0-9
[:cntrl:] 控制字符 ctrl、backspace等等
[:lower:] 小写字母 a-z
[:upper:] 大写字母 A-Z
[:digit:] 十进制数 0-9
[:xdigit:] 十六进制数 0-9a-fA-F
[:punct:] 标点符号 ,.?:‘ "
[^[:alpha:]] 取反,表示不是字母
~# grep "[[:space:]]\.[[:digit:]][[:space:]]" datafile --color
southwest SW Lewis Dalsass 2.7 .8 218
southeast SE Patricia Hemenway 4.0 .7 417
| 或者
? 表示0个或者1个它前面的字符 a?d ==> d ad
+ 表示1个或者多个它前面的字符 a+d ==> ad aad aaad ... ...
()
x{m}
x{m,}
x{m,n}
|
显示datafile文件中含有NW或者是WE的行
~# egrep "NW|WE" datafile --color
~# grep -E "NW|WE" datafile --color
?
~# egrep "2\.?[0-9]" datafile --color
+
~# egrep "a+" e2.txt --color
aabbcc
aaabbbccc
aaaannnmms
三.sed
sed 流编辑器 stream editor
是一种非交互式文本编辑器,默认是不会修改原文件的
工作原理
一行一行处理的
从文件的第一行开始读取,放到模式空间中进行相应处理,处理完将结果输出到屏幕上,然后继续读取下一行,直到所有的行都处理完毕,sed结束。
sed一般用于处理大文件。
语法:
sed [选项] ‘AddressCommand‘ 文件列表
1、常用的选项
-n:静默输出,关闭模式空间的输出,一般与p一起用
-e:允许进行多项编辑,也就是说对同一行做多次处理、也可以做多点编辑
-e ‘动作‘ -e ‘动作‘ 等价于 ‘动作1;动作2‘
-f sed脚本 : 指定运行的sed脚本的
-r:允许使用扩展正则
-i:直接修改原文件
2、Address : 定址、地址
1)单独的行号
如: 1 就表示要处理第一行
$ 表示最后一行
2)起始行,结束行
如: 1,5 处理第一行到第五行
3)/正则表达式/
如:/^root/ 处理以root开头的行
4)/正则表达式1/,/正则表达式2/ 最小匹配
表示处理从匹配到正则表达式1的行开始,到第一次匹配到正则表达式2之间的所有行
如果正则表达式1匹配到了,正则表达式2未匹配到,那么就从匹配到正则表达式1的行开始,一直处理到文件结束
如果正则表达式1未匹配到,那么就不对文件做处理。
如:/^bin/,/bash$/
binsdadaddaddass
dsfasidsfdhfj09bash
dasdasdasdf--bash
5)起始位置,+N 不是特别常用
表示从起始位置开始,后面的N行都处理
如:3,+5 处理3-8行
3、Command
常用的:d p s y q
其他的:a c i r w
h H g G
1)d:删除
~# sed ‘/UUID/d‘ /etc/fstab
~# sed ‘1,5d‘ /etc/fstab
~# sed ‘$d‘ /etc/fstab
~# sed ‘/tmp/,/sfs/d‘ /etc/fstab
~# sed ‘/UUID/,+5d‘ /etc/fstab
删除从第5行开始到最后一行的所有内容
~# sed ‘5,$d‘ /etc/passwd
2)p:打印
~# cat -n /etc/passwd | head > pass
~# sed ‘p‘ pass //每行会打印两遍,一遍是处理结果,一遍是模式空间的输出
~# sed -n ‘p‘ pass //只会打印一遍,因为模式空间的输出被关闭了
~# sed -n ‘3,5p‘ pass // 打印文件的3到5行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
~# sed -n ‘3p‘ pass
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
! 非
~# sed ‘3!d‘ pass //等价于打印第3行
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
练习:
用sed分别实现head -1 和 tail -1的功能
head -1
~# sed -n ‘1p‘ pass
1 root:x:0:0:root:/root:/bin/bash
~# sed ‘1!d‘ pass
1 root:x:0:0:root:/root:/bin/bash
tail -1
~# sed -n ‘$p‘ pass
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
~# sed ‘$!d‘ pass
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
3)r 读取
~# sed ‘/^root/r /etc/issue‘ /etc/passwd
1 root:x:0:0:root:/root:/bin/bash
Red Hat Enterprise Linux Server release 6.4 (Santiago)
Kernel \r on an \m
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
4)w 写
~# sed ‘/root/w /tmp/douni‘ pass //将匹配到的行另存到文件中
~# cat /tmp/douni
1 root:x:0:0:root:/root:/bin/bash
5)a 追加 在匹配到的行的下一行插入内容
~# sed ‘/root/a hello root‘ pass | head -5
1 root:x:0:0:root:/root:/bin/bash
hello root
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
在文件的最后一行插入新内容
~# sed ‘$a The End‘ pass
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
The End
6)i 插入 在匹配行的上一行插入内容
~# sed ‘/daemon/i SO COOL‘ pass | head -5
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
SO COOL
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
~# sed ‘1i BEGINNING‘ pass | head -5 //在第一行插入内容
BEGINNING
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
7)c 修改 本行替换,将匹配到的行的内容替换成新内容
~# sed ‘/root/c ROOT‘ pass
1 ROOT
ROOT:x:0:0:root
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
~# sed ‘/IPADDR/c IPADDR=172.16.254.201‘ /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=no
BOOTPROTO=static
IPADDR=172.16.254.201
NETMASK=255.255.0.0
GATEWAY=172.16.254.1
8)y 转换的命令,对应替换
y///
y/123/ABC/
~# sed ‘y/1234/ABCF/‘ pass
A root:x:0:0:root:/root:/bin/bash
B bin:x:A:A:bin:/bin:/sbin/nologin
C daemon:x:B:B:daemon:/sbin:/sbin/nologin
F adm:x:C:F:adm:/var/adm:/sbin/nologin
5 lp:x:F:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:AB:mail:/var/spool/mail:/sbin/nologin
A0 uucp:x:A0:AF:uucp:/var/spool/uucp:/sbin/nologin
将文件中所有的小写字母转换成大写字母
~# sed ‘y/qwertyuiopasdfghjklzxcvbnm/QWERTYUIOPASDFGHJKLZXCVBNM/‘ pass
9)n next 处理匹配行的下一行,用的较少
~# sed -n ‘/root/p‘ pass
1 root:x:0:0:root:/root:/bin/bash
~# sed -n ‘/root/{n;p}‘ pass //{}里面写多个命令,之间用分号分隔
2 bin:x:1:1:bin:/bin:/sbin/nologin
10)q 退出 不再向模式空间读入新行
~# sed ‘/^bin/q‘ /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
~# sed ‘1q‘ pass //head -1的又一种方法
1 root:x:0:0:root:/root:/bin/bash
练习:
1、将pass文件每行打印3次
~# sed ‘p;p‘ pass
2、打印passwd文件的第1行和第3行(多点编辑,用分号分隔命令)
~# sed -n ‘1p;3p‘ pass
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed -n -e ‘1p‘ -e ‘3p‘ pass
3、使用sed修改selinux的模式为permissive
~# sed ‘7c SELINUX=permissive‘ /etc/selinux/config
4、使用sed永久修改主机名为shell
~# sed ‘$c HOSTNAME=shell‘ /etc/sysconfig/network
3、删除pass文件的第1行和最后一行
~# sed ‘1d;$d‘ pass
以下操作datafile文件
4、在匹配到Lewis的行的下一行插入“has Lewis”
~# sed ‘/Lewis/a has Lewis‘ datafile
5、在文件的第一行插入“employee‘s information”
~# sed "1i employee‘s information" datafile
11)s 查找替换
定址s/模式匹配(旧的内容)/新的内容/[修饰符]
s@@@ s### s%%%
修饰符:
g:全局替换,一行中的多个
n:n为数字,1-512 替换第n个匹配到的内容
p:打印
w:另存为,写
~# sed ‘s/root/ROOT/‘ pass | head -3 //默认只替换第一次匹配到的
1 ROOT:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed ‘s/root/ROOT/2‘ pass | head -3 //替换每行中第2个匹配到的
1 root:x:0:0:ROOT:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
~# sed ‘s/root/ROOT/g‘ pass | head -3 //全部替换
1 ROOT:x:0:0:ROOT:/ROOT:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
练习:
1、从以root开头,到以login结尾的行,将sbin替换成bin (/etc/passwd)
~# sed ‘/^root/,/login$/s/sbin/bin/‘ /etc/passwd | head
2、将格式为2015/09/02的日期,替换为2015; 09; 02的格式(注意分号后面有空格)
~# date "+%Y/%m/%d"
2015/09/02
~# date "+%Y/%m/%d" | sed ‘s#/#; #g‘
2015; 09; 02
~# date "+%Y/%m/%d" | sed ‘s/\//; /g‘
3、将selinux配置文件中的disabled替换为enforcing,暂时不作用于原文件
~# sed ‘/SELINUX/s/disabled/enforcing/‘ /etc/selinux/config
思考题:删除文件中所有的数字 **** //一种思想,用替换去删除字符等
~# sed ‘s/[0-9]//g‘ pass
-i:直接作用于文件
~# sed ‘s/static/dhcp/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
~# sed -i ‘s/static/dhcp/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
~# sed -i.bak ‘s/dhcp/static/‘ /etc/sysconfig/network-scripts/ifcfg-eth0
//.bak是备份文件的后缀名
~# ls /etc/sysconfig/network-scripts/ifcfg-eth0*
ifcfg-eth0 ifcfg-eth0.bak
模式匹配时的特殊符号
^:每行的开头
给全文加注释
~# sed ‘s/^/#/‘ pass
在第8到10行的开头每行加上###
~# sed ‘s/^/###/‘ pass
$:每行的结尾
在匹配到root的行的末尾添加###
~# sed ‘/root/s/$/###/‘ pass
1 root:x:0:0:root:/root:/bin/bash###
-r选项: 支持扩展正则
~# sed -r ‘s/[[:space:]]+//‘ pass
~# sed ‘s/[[:space:]]*//‘ pass
1、将history命令执行结果中编号前面的空白字符删掉
~# history | sed -r ‘s/[[:space:]]+//‘
2、删除文件中的空行和空白行
~# cat txt
adadadadada dasdasdadas
dadada
gdfgdgdfgfdg
~# cat -A txt
adadadadada dasdasdadas$
$
$
dadada $
^I^I $
gdfgdgdfgfdg$
~# sed -r ‘/^$/d;/^[[:space:]]+$/d‘ txt
adadadadada dasdasdadas
dadada
gdfgdgdfgfdg
& 引用 用来代替匹配到的模式的
将每一行的行号加上括号
~# sed -r ‘s/[0-9]+/(&)/‘ pass
~# vim test
hello, i like you
hi, my love
like ==> liker
love ==> lover
~# sed ‘s/l..e/l..er/‘ test
hello, i liker you
hi, my lover
~# sed -r ‘s/(l..e)/\1r/‘ test
hello, i liker you
hi, my lover
like ==> Like
love ==> Love
~# sed -r ‘s/l(..e)/L\1/‘ test
hello, i Like you
hi, my Love
练习:
1、删除每行的第一个字符
2、删除每行的第二个字符
3、删除每行的倒数第一个字符
4、删除每行的倒数第二个字符
5、交换每行的第一个和第二个字符
思考:
删除/etc/passwd每行的第一个字段
交换/etc/passwd文件的第一个和第二个字段
作业:
1、将/etc/inittab文件中的id:5:initdefault中的5替换成3
以下使用datafile3
1、将Jon的名字改为Jonathan
2、删除文件的前3行
3、打印文件的第5到10行
4、删除含有Lane的行
5、打印生日在11月和12月的行
6、在以Fred开头的行末尾添加三个*
7、将所有包含Jose的行替换为Match Jose
8、把Popeye的生日改为11/14/46,前提:需要你先匹配出生日
9、删除所有的行
10、将文件中的所有大写字母用括号()括起来
每多少行操作一次
first~step
first:起始行号
step:步长
打印偶数行
~# sed -n ‘2~2p‘ pass
2 bin:x:1:1:bin:/bin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
8 halt:x:7:0:halt:/sbin:/sbin/halt
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
每3行打印一次
~# sed -n ‘1~3p‘ pass
1 root:x:0:0:root:/root:/bin/bash
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
=:打印当前行号
统计文件的行数
~# sed -n ‘$=‘ /etc/passwd
76
~# vim sc1.sed
/Lewis/a \
hello everyone \
ni hao
/Suan/c has suan
1i \
************** \
begin \
**************
$d
调用脚本
~# sed -f sc1.sed datafile
**************
begin
**************
northwest NW Charles Main 3.0 .98 334
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 218
hello everyone
ni hao
has suan
southeast SE Patricia Hemenway 4.0 .7 417
eastern EA TB Savage 4.4 .84 520
northeast NE AM Main Jr. 5.1 .94 313
western WE Sharon Gray 5.3 .97 5 23
north NO Margot Weber 4.5 .89 59
模式空间
用于处理文本行的
PATT,最多能够存储8192字节
保留空间
用于保留文本行的
HOLD,sed用来保存已经处理过的文本行的,最多保存8192字节,默认有一个空行
涉及到的命令
h:将模式空间的内容复制到保留空间 —— 覆盖模式
H:将模式空间的内容追加到保留空间 —— 追加模式
g:将保留空间的内容复制到模式空间 —— 覆盖模式
G:将保留空间的内容追加到模式空间 —— 追加模式
x:将模式空间的内容和保留空间的内容进行交换
交换第一行和第二行的内容
~# sed ‘1{h;d};2G‘ pass | head -5
2 bin:x:1:1:bin:/bin:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
将第1行到第3行的内容复制到第4行后面
~# sed ‘1h;2,3H;4G‘ pass | head
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
将第1行到第3行的内容剪切到第4行的后面
~# sed ‘1{h;d};2,3{H;d};4G‘ pass
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
在每行的下面添加一个空行
~# sed ‘G‘ pass
思考:倒序输出文件的每一行
假设文件如下:
aa
bb
cc
dd
要求输出结果如下:
dd
cc
bb
aa
四.awk
awk 一种编程语言、文本编辑器、也是一种非交互式的编辑器
功能:对文本数据进行汇总和处理,是一个报告的生成器,能够对数据进行排版
awk nawk gawk posix awk
nawk —— solaris
gawk,awk —— GNU Linux
工作过程
将文件中的内容逐行的进行扫描,把整行内容存入内置变量$0中;
再按照指定的分隔符(默认的分隔符是空白)将输入行切成若干个列(字段),存入变量$1~$100,再使用命令(print、printf)将变量打印输出,输出分隔符默认也是空白
再读取下一行,循环处理,直到文件处理结束。
~# ifconfig eth0 | grep Bcast | awk ‘{print $2}‘ | awk -F: ‘{print $2}‘
172.16.254.200
~# df -h / | tail -1 | awk ‘{print $5}‘ | cut -d"%" -f1
18
1、awk的语法
awk [选项] ‘/模式匹配(定址)/{处理动作1;处理动作2;... ...; 处理动作n}‘ 文件列表
2、简单操作
~# head /etc/passwd > pass
打印pass文件中的用户名和uid
~# awk -F: ‘{print $1,$3}‘ pass
-F:指定输入文件字段分隔符
3、语法中的说明
1)设定输入分隔符 -F
分隔符可以是数字、字母、符号和空白
可以同时指定多个分隔符 : / ,
默认是空白
---- 单个符号的分隔符
-F:
---- 复合分隔符,多个字符组成一个分隔符
:/
pass文件以:/为分隔符,打印第一个字段
~# awk -F":/" ‘{print $1}‘ pass
---- 同时指定多个分隔符
:和/都是分隔符
~# awk -F"[:/]" ‘{print $1,$10}‘ pass
---- 以空为分隔符
~# awk -F "" ‘{print $1,$2}‘ pass //注意:-F后面有空格
2)awk输出
(1)print
打印内容的,内容可以是文件中的内容,也可以跟文件内容毫无关系
~# awk ‘{print "hello"}‘ pass //打印内容和文件不相关,只是借用了pass文件的行,有多少行内容,hello就会被打印多少次
打印每一行的内容
~# awk ‘{print $0}‘ pass
~# awk ‘{print}‘ pass
\n :换行符
~# head -1 pass | awk ‘{print "hello\nworld"}‘
hello
world
\t : 制表符
~# head -1 pass | awk ‘{print "hello\tworld"}‘
hello world
~# awk -F: ‘{print $1"\t"$3}‘ pass
print要点:
a、各个输出字段之间用逗号分隔,而输出的时候默认是以空白为分隔符的
b、print后面如果不跟字段,那么默认打印整行
c、print输出时默认是有换行的
1、在每行的下面打印一个空行
~# awk ‘{print $0"\n"}‘ pass
2、使用awk取出eth0网卡的IP地址
~# ifconfig eth0 | awk ‘/Bcast/{print $2}‘ | cut -d: -f2
172.16.254.200
(2)printf —— 可以格式化输出的,默认没有换行
使用格式
printf format,item1,item2,... ...,itemn
format的指示符都是以%开头的,后面跟一个字符,如:
%s:表示是字符串
%d:表示十进制数
%f: 表示浮点数,其实就是小数 float
%%:表示%本身
%x:表示十六进制数
%o:表示八进制数
%c:表示字符
修饰符: N(数字) 表示显示宽度 %10s
- 表示左对齐,默认是右对齐 %-10s
对于浮点数:
%5.2f : 其中5表示总的显示宽度(整数位+小数位),2表示小数位的位数
%-5.2f
%.2f :表示整数位全部保留,小数位保留两位
~# awk -F : ‘{printf "%10s%5d",$1,$3}‘ pass //默认printf是没有换行的
root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 uucp 10~#
~# awk -F : ‘{printf "%10s%5d\n",$1,$3}‘ pass
~# awk -F : ‘{printf "%-10s%5d\n",$1,$3}‘ pass
%d直接取整,不进行四舍五入;%f进行四舍五入的
~# echo "12.64 23.456 11.2345" > test
~# awk ‘{printf "%d\n",$1}‘ test
12
~# awk ‘{printf "%.2f\n",$2}‘ test
23.46
printf要点:
a、与print不同的是,printf需要指定格式
b、格式其实是用来指定后面每个条目的输出格式的
c、printf默认不会自动打印换行符的,有需要时候手动指定"\n"
d、默认没有输出分隔符
~# awk ‘{printf "%d%d\n",$1,$2}‘ test
1223
~# awk ‘{printf "%d %d\n",$1,$2}‘ test
12 23
练习:
格式化输出passwd文件中的用户名,UID,shell三列
~# awk -F: ‘{printf "%-15s%-6d%-15s\n",$1,$3,$7}‘ /etc/passwd
3)awk的操作符
(1)算数运算符
-x:表示负数 +x(x):表示正数
x+y x-y x*y x/y x%y x**y 等价于 x^y(x的y次幂)
~# awk ‘{print $3+$5}‘ employees
547778
34111
651654
338183
~# awk ‘{print $3+$5,$3-$5,$3*$5,$5/$3,$5%$3}‘ employees
547778 -538930 2403798096 122.82 3626
34111 -23419 153777690 5.38066 2035
651654 -648346 1075100000 392.987 1632
338183 -334817 566329500 199.941 1583
~# echo hello | awk ‘{print 2^16}‘
65536
~# awk ‘{printf "%-10d\n",$5+$3}‘ employees
547778
34111
651654
338183
(2)关系运算符
a、数值之间的关系运算符
> < >= <= == !=
打印uid小于等于10 的行
~# awk -F: ‘$3<=10{print $0}‘ /etc/passwd
~# awk -F: ‘$3<=10{print}‘ /etc/passwd
~# awk -F: ‘$3<=10‘ /etc/passwd
b、字符串之间的关系运算符
== !=
$1=="root"
$1!="root"
~# awk -F: ‘$1=="root"‘ pass
root:x:0:0:root:/root:/bin/bash
x ~ /y/ —— 匹配正则 其中y可以是正则表达式
打印用户名中含有o的用户的名字
~# awk -F: ‘$1 ~ /o/{print $1}‘ pass
root
daemon
shutdown
x !~ /y/ —— 不匹配正则
~# awk -F: ‘$1 !~ /o/{print $1}‘ pass
bin
adm
lp
sync
halt
uucp
练习:
1、打印/etc/fstab中含有boot的行
~# awk ‘/boot/‘ /etc/fstab
~# awk ‘$0 ~ /boot/‘ /etc/fstab
2、打印/etc/passwd文件中的uid为10的用户的用户名、uid及家目录
~# awk -F: ‘$3==10{print $1,$3,$6}‘ /etc/passwd
uucp 10 /var/spool/uucp
3、打印用户shell为登录shell的用户名及shell
~# awk -F: ‘$7 ~ /sh$/{print $1,$7}‘ pass
root /bin/bash
(3)逻辑运算符
&& || !
打印uid在5到10之间的用户的用户名,UID
~# awk -F: ‘$3>=5 && $3<=10{print $1,$3}‘ /etc/passwd
sync 5
shutdown 6
halt 7
mail 8
uucp 10
打印uid大于10或者uid小于5的用户名
~# awk -F: ‘$3<5 || $3>10{print $1,$3}‘ /etc/passwd
打印uid不大于3的用户名
~# awk -F: ‘!($3>3){print $1,$3}‘ pass
(4)赋值运算符
= += -= *= /= %= **= ^=
++ --
sum+=$3
练习:
1、打印uid和gid不相同的用户的用户名、uid、gid
~# awk -F: ‘$3!=$4{print $1,$3,$4}‘ /etc/passwd
2、交换pass文件的第一个字段和第二个字段
~# awk -F: ‘{print $2":"$1":"$3":"$4":"$5":"$6":"$7}‘ pass
3、打印100以内能够被7整除,以及包含7 的数
~# seq 100 | awk ‘$0%7==0 || $0 ~ /7/‘
~# seq 100 | awk ‘$0%7==0 || /7/‘
4、awk的模式匹配(即定址) —— awk + 正则表达式
常见的模式
1)空模式:也就是每一行都要做处理的模式
~# awk -F: ‘{print $1}‘ pass
2)正则表达式
a、固定定址
~# awk -F: ‘/^ro/{print $1}‘ pass
root
b、范围定址
~# awk -F: ‘/^ro/,/^lp/{print $1}‘ pass
root
bin
daemon
adm
lp
注意:awk是不支持行号定址的
反例:
~# awk -F: ‘2{print $1}‘ pass
3)表达式
$3>=5
$7 ~ /sh$/
4)特殊模式
BEGIN {}
END {}
5)NR变量定址
NR>1 //行号大于1的行
5、awk的变量
种类:内置变量、自定义的变量
1)内置变量
(1)$0 表示一整行的内容
(2)$1 ~ $100
$1:第一列
(3)与记录相关的变量(记录就是行)
FS(field separator):字段分隔符,默认是空白
FS=":"
OFS(Output):输出字段分隔符
RS(record):记录的分隔符,即行的分隔符
ORS:输出记录分隔符
(4)与数据相关的变量
NR(Number of Record):记录数,awk的处理的行的总数 NR在很多情况下可以看成行号
NF(Number of Field):当前行的字段数
$NF:当前行的最后一个字段的值
$(NF-1):当前行的倒数第二个字段
~# cat employees
Tom Tom 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
Tom Tom 4424 5/12/66
~# awk ‘{print NR":"NF":"$NF}‘ employees
1:5:543354
2:5:28765
3:5:650000
4:5:336500
5:4:5/12/66
打印pass文件的第2行
~# awk ‘NR==2‘ pass
bin:x:1:1:bin:/bin:/sbin/nologin
2)自定义变量
命名:由字母、数字、下划线组成,不能以数字开头,不能使用关键字,最好见名知意
变量名区分大小写
变量可以先定义再使用,也可以直接使用
给变量赋值
变量名=数值
a=5
变量名="字符串" //注意:此处一定有引号
username="root"
~# echo hello | awk ‘{num=5;pass="douniwan";print num,pass}‘
5 douniwan
练习:
1、打印passwd文件的奇数行的行号和内容
NR%2==1 或者 NR%2!=0
2、打印每行的倒数第三个字段(employees文件)
$(NF-2)
3、从第一行开始,每3行打印一次(即打印行号为1 4 7... 这样的行)
NR%3==1
4、输出以 : 和 / 为分隔符的情况下,passwd文件的最后一列
-F"[:/]" $NF
5、打印/etc/passwd文件的偶数行
NR%2==0
6、打印pass文件中没有指定shell的用户名(文件自己处理一下,可以将某个或者某几个的shell删除掉)
-F: $7 == ""
$7 ~ /^$/
7、打印passwd文件的第3行和第5行
NR==3 || NR==5
sed相关练习
1、将passwd文件 中的第20行到第30行的内容复制到第33行后面,同时显示行号(可以使用除了sed以外的命令)
cat -n passwd | sed ‘20h;21,30H;33G‘
2、写sed脚本 处理文件为datafile3
1)在第一行插入标题:EMPLOYEES
2)删除以500为结尾的行的工资项(注意:不是删除行,只是删除工资那个段)
3)将名和姓的位置颠倒输出
4)在文件末尾添加OVER
1i EMPLOYEES
s/:[0-9]*500$/:/
s/^([A-Z][a-z]*) ([A-Z][a-z]*)/\2 \1/
$a OVER
sed -rf script.sed datafile3
--------------------------------------------------------------------------------------
6、赋值运算
a+=$2 等价于 a=a+$2
a+=5
-= *= /= %= ^=
a++ ++a
a-- --a
~# echo hello | awk ‘{a=5;b=a++;print a,b}‘
6 5
~# echo hello | awk ‘{a=5;b=++a;print a,b}‘
6 6
练习:
1)把employees里面最后一个字段的值减去8,打印
~# awk ‘{print $NF-8}‘ employees
543346
28757
649992
336492
2)将employees倒数第三列对3取余并打印
~# awk ‘{print $(NF-2)%3}‘ employees
2
0
1
0
0
~# awk ‘{a=$(NF-2)%3;print a}‘ employees
2
0
1
0
0
7、awk的特殊模式
awk的完整语法
awk [选项] ‘BEGIN{动作}定址{动作}END{动作}‘ 文件列表
BEGIN{} : 在读取文件之前就执行,只执行一次;一般用于初始化分隔符、初始化变量、定义数组、打印表头等
定址{} : 这一部分可能会执行多次
END{} : 在处理完文本之后执行,只执行一次;一般用于汇总数据 比如:打印总成绩、平均成绩等等
~# awk ‘BEGIN{FS=":";print "username"}/root/{print $1}END{print "over"}‘ /etc/passwd
username
root
operator
over
说明:
BEGIN和END可以单独存在的
1)只有BEGIN,后面不需要加文件
~# awk ‘BEGIN{print "hello"}‘
hello
2)只有END,后面必须加文件,文件可以是空文件,也可以是有内容的文件
~# awk ‘END{print "end"}‘ pass
end
~# touch haha
~# awk ‘END{print "end"}‘ haha
end
3)没有BEGIN,也没有END
~# awk ‘{sum=0;sum+=$3;print $1,$3,sum}‘ employees
Tom 4424 4424
Mary 5346 5346
Sally 1654 1654
Billy 1683 1683
Tom 4424 4424
4)有BEGIN,没有END‘
~# awk ‘BEGIN{sum=0}{sum+=$3;print $1,$3,sum}‘ employees
Tom 4424 4424
Mary 5346 9770
Sally 1654 11424
Billy 1683 13107
Tom 4424 17531
5)既有BEGIN,又有END
~# awk ‘BEGIN{sum=0}{sum+=$3;print $1,$3}END{print "total:"sum}‘ employees
Tom 4424
Mary 5346
Sally 1654
Billy 1683
Tom 4424
total:17531
练习:
统计/etc目录下所有的普通文件的总大小
~# ll /etc | awk ‘BEGIN{sum=0}/^-/{sum+=$5}END{print sum}‘
1257642
8、awk的脚本
BEGIN{
命令
}
定址{
命令
}
END{
命令
}
打印ule总成绩,平均成绩
~# vim sc.awk
BEGIN{
print "This is ule score table"
}
NR>1{
ule+=$2
}
END{
print "ule‘s total score is :"ule
print "ule‘s average score is :"ule/(NR-1)
}
~# awk -f sc.awk score
This is ule score table
ule‘s total score is :246
ule‘s average score is :61.5
练习:
1、求得ULA的总成绩,平均成绩;求oracle的总成绩,平均成绩
2、样例文件staff.txt
文件内容如下:
~# cat staff.txt
id name sal date
100 tom 10000 2013/10/1
101 jerry 8000 2013/10/10
102 john 5000 2013/11/1
103 mark 6000 2013/12/10
104 rose 2000 2014/01/01
105 jake 1500 2014/01/10
1)统计每个月发出去的总工资
~# awk ‘NR>1{sal+=$3}END{print sal}‘ staff.txt
32500
NR>1{
sal+=$3
}
END{
print sal
}
2)统计2013年入职的人数
~# awk ‘/2013/{count++}END{print count}‘ staff.txt
4
3)统计工资超过5000的有几个人
~# awk ‘$3>5000 && NR>1 {count++}END{print count}‘ staff.txt
3
1、awk与重定向
passwd
将uid>100的用户名及uid保存到/tmp/uidup100文件中
~# awk -F: ‘$3 > 100{print $1,$3 > "/tmp/uidup100"}‘ /etc/passwd
输入重定向 getline
getline 接收来自于标准输入、管道和文件(非当前处理文件)的数据,存入到一个变量中,再给awk使用
~# awk ‘BEGIN{"date" | getline a}{print $0}END{print a}‘ pass
~# tty
/dev/pts/10
从标准输入读取一个数据,传给变量username,判断passwd文件中是否有这样的用户名,如果有,打印行号和用户名
~# vim sc2.awk
BEGIN{
FS=":"
printf "请输入一个用户名: "
getline username < "/dev/pts/10"
}
{
if($1==username) 判断
{
print NR,$1
}
}
~# awk -f sc2.awk /etc/passwd
请输入一个用户名: root
1 root
2、awk与管道
~# awk -F: ‘$3 > 100{print $1,$3 | "sort -nr -k2"}‘ /etc/passwd
3、使用awk执行系统命令
~# awk ‘BEGIN{print "today is ";system("date")}‘
today is
Mon Sep 7 12:26:03 CST 2015
基本的结构
1、顺序结构
2、分支判断 if
3、循环结构 while for 循环控制语句:break continue exit next
一、三元操作符
?:
判断条件?输出结果1:输出结果2
如果条件为真,输出问号后面的结果,否则输出冒号后面的结果
~# awk -F: ‘{print $1":"($3>$4?"uid:"$3:"gid:"$4)}‘ pass
二、分支判断结构 if
1、语法格式:
if(条件表达式) —— 注意:如果if是写在awk的脚本中,那么他的整体都要写在{}中,因为它属于动作
{
动作
}
else
{
动作
}
修改三元操作符的小练习
~# vim if1.awk
BEGIN{
FS=":"
}
{
if($3>$4)
{
print $1":uid:"$3
}
else
{
print $1":gid:"$4
}
}
~# awk -f if1.awk pass
2、多分支判断语法结构
if(条件表达式)
{
动作
}
else if(条件表达式)
{
动作
}
... ...
else
{
动作
}
~# cat if2.awk
#!/usr/bin/awk -f //shabang,指定文件中的命令的解析环境是awk
NR>1{
if($2>=90)
{
print $1": A"
}
else if($2>=80)
{
print $1": B"
}
else
{
print $1": C"
}
}
~# chmod +x if2.awk
~# ./if2.awk score
mike: B
rose: C
john: A
larry: C
练习:
统计ula成绩在以下每个分数段的人数
>=90
>=80
>=70
打印效果:
成绩在90分以上的有__人
成绩在80分到90分之间的有__人
成绩在70分到80分之间的有__人
~# cat if3.awk
#!/usr/bin/awk -f
NR>1{
if($3>=90)
{
up90++
}
else if ($3>=80)
{
up80++
}
else if($3>=70)
{
up70++
}
}
END{
printf "成绩在90分以上的有%d人\n",up90
printf "成绩在80分到90分之间的有%d人\n",up80
printf "成绩在70分到80分之间的有%d人\n",up70
}
~# chmod +x if3.awk ^C
~# ./if3.awk score
成绩在90分以上的有1人
成绩在80分到90分之间的有1人
成绩在70分到80分之间的有1人
三、循环
功能:
1)从行中取出每个字段,循环字段的
2)遍历数组元素
1、while循环
语法:
变量初始值
while (条件)
{
动作
变量的更新
}
mike
85
80
90
~# vim while1.awk
/mike/{
i=1
while(i<=NF)
{
print $i
i++
}
}
~# awk -f while1.awk score
mike
85
80
90
练习:
1)将passwd文件的第一行的每个字段纵向打印
输出结果如下:
root
x
0
0
root
/root
/bin/bash
~# cat while2.awk
BEGIN{
FS=":"
}
NR==1{
i=1
while(i<=NF)
{
print $i
i++
}
}
2)倒序输出passwd文件的每一列
结果例如(以一行为例)
/bin/bash:/root:root:0:0:x:root
法一:
~# awk ‘BEGIN{FS=":";OFS=":"}{print $7,$6,$5,$4,$3,$2,$1}‘ pass
法二:
~# cat while4.awk
BEGIN{
FS=":"
}
{
i=NF
while(i>1)
{
printf $i":"
i--
}
print $1
}
2、for循环
语法:
for(变量初始值;判断条件;变量的更新)
{
动作
}
~# vim for1.awk
/mike/{
for(i=1;i<=NF;i++)
{
print $i
}
}
四、判断加循环
~# awk ‘NR>1{print $2,$3,$4}‘ score > number
例子:
输出每行的最大值
~# vim if-for.awk
{
max=$1
for (i=1;i<=NF;i++)
{
if($i>max)
{
max=$i
}
}
print max
}
~# awk -f if-for.awk number
90
70
91
100
五、双重循环 (嵌套循环)
打印99乘法口诀表
~# vim for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
printf j"*"i"="i*j"\t"
}
printf "\n"
}
}
~# awk -f for-for.awk
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
六、循环控制语句
continue 跳出本次循环
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {continue}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
break 跳出当前循环
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {break}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
exit 退出脚本
~# cat for-for.awk
BEGIN{
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
if (j==4) {exit}
else
{
printf j"*"i"="i*j"\t"
}
}
printf "\n"
}
}
next 跳过本行,读取下一行
~# awk ‘/name/{next};{print $0}‘ score
数组: array
数组是使用一个变量名 来保存一组数据,通常这些数据的类型是一样的
数组中的数据(元素) 是与数组下标一一对应的
如果想要取出数组中的某个元素,就会使用到数组名和下标
awk中的数组也成为关联数组,是因为它的下标可以是数值,也可以是字符串
一、数组的定义
数组名[下标]=值
二、数组的遍历
for循环遍历数组
语法:
1)for (i=0;i<NR;i++)
2) for (下标 in 数组名) {print 数组名[下标]}
定义数组及给数组中元素赋值
~# vim arr.awk
BEGIN{
a[1]="aa"
a[2]="bb"
a[3]="cc"
for(i=1;i<=3;i++)
{
print a[i]
}
}
~# awk -f arr.awk
aa
bb
cc
awk支持的下标的类型
1)使用数字或变量作为下标
name[1] name[x++] name[NR]
~# awk ‘{name[x++]=$1}END{for(i=0;i<NR;i++){print i,name[i]}}‘ employees
0 Tom
1 Mary
2 Sally
3 Billy
4 Tom
2)使用字符串做下标
name["tom"]++
~# vim datafile4
cat
dog
pig
cat
dog
dog
bird
dog
rabbit
统计文件中每种动物有几只?
~# awk ‘{count[$1]++}END{for(i in count){print i,count[i]}}‘ datafile4
cat 2
bird 1
rabbit 1
dog 4
pig 1
统计apache日志中每个IP的访问次数,显示访问次数最多的五个IP及访问次数
统计/root/.bash_history文件中执行次数最多的十条命令
统计系统中使用每种shell的有几个人?
统计服务器上tcp连接情况(每种监听状态有几个?)
如:
LISTEN 10
ESTABLISHED 30
~# netstat -ant
内置函数
自定义函数
一、内置函数
man awk //搜索Function
1、sub(正则表达式,替换字符串) —— 查找并替换
~# awk ‘{sub(/NW/,"NorthWest");print}‘ datafile
northwest NorthWest Charles Main 3.0 .98 3 34
2、tolower(字符串) —— 转换成小写
toupper(字符串) —— 转换成大写
~# awk ‘{print toupper($1)}‘ datafile
~# awk ‘{print tolower($2)}‘ datafile
3、index(原字符串,子串) —— 输出子串在原字符串中的位置
~# awk ‘{print index($1,"o"),$1}‘ datafile
2 northwest
0 western
2 southwest
2 southern
2 southeast
0 eastern
2 northeast
0 western
2 north
0 central
4、length(字符串) —— 显示字符串的长度
~# awk ‘{print length($1),$1}‘ datafile
9 northwest
7 western
9 southwest
8 southern
9 southeast
7 eastern
9 northeast
7 western
5 north
7 central
二、自定义函数
格式
function 函数名(参数1,参数2,... ... ,参数n) {
函数体
return value //返回值
} //参数也是可有可无的
~# awk ‘function hello(){print "shell is over"}{hello()}‘ pass
评论(0)