sed常见的语法格式有两种,一种叫命令行模式,另一种叫脚本模式。
sed -option 'commands[地址定位]' filename
说明:引用shell script中的变量应使用双引号,而非通常使用的单引号
option:
-e 进行多项编辑,即对输入行应用多条sed命令时使用
-n 取消默认的输出
-f 指定sed脚本的文件名
-r 使用扩展正则表达式 + ? {} () |
-i inplace,原地编辑(修改源文件)
xp 打印行
d 删除行
i\ 在当前行之前插入文本。多行时除最后一行外,每行末尾需用"\"续行
a\ 在当前行后添加一行或多行。多行时除最后一行外,每行末尾需用“\”续行
c\ 用此符号后的新文本替换当前行中的文本。多行时除最后一行外,每行末尾需用"\"续行
[root@MissHou shell05]# sed 'i\
aaaaa\
bbbbb\
88888' 1.txt
r 从文件中读取输入行
w 将所选的行写入文件
! 对所选行以外的所有行应用命令,放到行数之后
# sed -n '1!p' 1.txt
s 用一个字符串替换另一个
g 在行内进行全局替换
& 保存查找串以便在替换串中引用
= 打印行号
定址用于决定对哪些行进行编辑。地址的形式可以是数字、正则表达式、或二者的结合。如果没有指定地址,sed将处理输入文件的所有行。
xxxxxxxxxx
x 指定x行号
x,y 指定x到y行号
/key/ 查询包含关键字的行
/key1/,/key2/ 匹配包含两个关键字之间的行
/key/,x 从匹配关键字的行开始到文件第x行之间的行(包含关键字所在行)
x,/key/ 从第x行开始到与关键字的匹配行之间的行
x,y! 不包含x到y行
注意:sed使用的正则表达式是括在斜杠线"/"之间的模式。
//以下命令是找出以lp开头或者以mail开头的行
说明:
-e 多次编辑
-r 扩展正则
xxxxxxxxxx
y命令
该命令与UNIX/Linux中的tr命令类似,字符按照一对一的方式从左到右进行转换。
正则表达式元字符对y命令不起作用。与s命令的分隔符一样,斜线可以被替换成其它的字符。
# sed '39,41y/stu/STU/' /etc/passwd
# sed '39,41y/stu:x/STU@%/' /etc/passwd
-e 选项 多项编辑
-e是编辑命令,用于sed执行多个编辑任务的情况下。在下一行开始编辑前,所有的编辑动作将应用到模式缓冲区中的行上。
-i 选项 直接修改原文件
# sed -i 's/root/ROOT/;s/stu/STU/' 11.txt
& 符号 保留查找字符串
# sed -n 's/^root/#&/p' passwd 注释掉以root开头的行
# sed -n -r 's/^root|^stu/#&/p' /etc/passwd 注释掉以root开头或者以stu开头的行
# sed -n '1,5s/^[a-z].*/#&/p' passwd 注释掉1~5行中以任意小写字母开头的行
# sed -n '1,5s/^/#/p' /etc/passwd 注释1~5行
或者
sed -n '1,5s/^/#/p' passwd 以空开头的加上#
sed -n '1,5s/^#//p' passwd 以#开头的替换成空
vim ——>ctrl+v——>I(行头插入)——>ESC
1140 sed -n '/^root/p' 1.txt
1141 sed -n 's/^root/#&/p' 1.txt
1142 sed -n 's/\(^root\)/#\1/p' 1.txt
1143 sed -nr '/^root|^stu/p' 1.txt
1144 sed -nr 's/^root|^stu/#&/p' 1.txt
= 打印行号
# sed -n '/bash$/=' passwd 打印以bash结尾的行的行号
# sed -ne '/root/=' -ne '/root/p' passwd
# sed -n '/nologin$/=;/nologin$/p' 1.txt
# sed -ne '/nologin$/=' -ne '/nologin$/p' 1.txt
q 退出
# sed '5q' 1.txt
# sed '/mail/q' 1.txt
# sed -r '/^yunwei|^mail/q' 1.txt
引申扩展:
h 把模式空间里的内容复制到暂存缓冲区
H 把模式空间里的内容追加到暂存缓冲区
g 取出暂存缓冲区的内容,将其复制到模式空间
G 取出暂存缓冲区的内容,将其复制到模式空间,追加在原有内容后面
x 交换暂存缓冲区与模式空间的内容
暂存和取用命令:h H g G
# sed '1H;$G' /etc/hosts
# sed '1h;$G' /etc/hosts
# sed '1h;$g' /etc/hosts
# sed '1{h;d};$G' /etc/hosts
# sed '1h;2,$g' /etc/hosts
# sed '1h;2,3H;$G' /etc/hosts
# sed '1!G;h;$!d' /etc/hosts
暂存空间和模式空间互换:x
# sed '4h;5x;6G' /etc/hosts
xxxxxxxxxx
# sed -f scripts.sed file //使用脚本处理文件
建议使用 ./sed.sh
脚本的第一行写上
#!/bin/sed -f
xxxxxxxxxx
1) 脚本文件是一个sed的命令行清单。
2) 在每行的末尾不能有任何空格、制表符(tab)或其它文本。
3) 如果在一行中有多个命令,应该用分号分隔。
4) 不需要且不可用引号保护命令
5) #号开头的行为注释
xxxxxxxxxx
# cat passwd
stu3:x:509:512::/home/user3:/bin/bash
stu4:x:510:513::/home/user4:/bin/bash
stu5:x:511:514::/home/user5:/bin/bash
# cat sed.sh
#!/bin/sed -f
2a\
******************
2,$s/stu/user/
$a\
we inster new line
s/^[a-z].*/#&/
xxxxxxxxxx
1、正则表达式必须以”/“前后规范间隔
例如:sed '/root/d' file
例如:sed '/^root/d' file
2、如果匹配的是扩展正则表达式,需要使用-r选来扩展sed
注意:
在正则表达式中如果出现特殊字符(^$.*/[]),需要以前导 "\" 号做转义
eg:sed '/\$foo/p' file
3、逗号分隔符
例如:sed '5,7d' file 删除5到7行
例如:sed '/root/,/ftp/d' file
删除第一个匹配字符串"root"到第一个匹配字符串"ftp"的所有行本行不找 循环执行
4、组合方式
例如:sed '1,/foo/d' file 删除第一行到第一个匹配字符串"foo"的所有行
例如:sed '/foo/,+4d' file 删除从匹配字符串”foo“开始到其后四行为止的行
例如:sed '/foo/,~3d' file 删除从匹配字符串”foo“开始删除到3的倍数行(文件中)
例如:sed '1~5d' file 从第一行开始删每五行删除一行
例如:sed -n '/foo|bar/p' file 显示配置字符串"foo"或"bar"的行
例如:sed -n '/foo/,/bar/p' file 显示匹配从foo到bar的行
例如:sed '1~2d' file 删除奇数行
例如:sed '0-2d' file 删除偶数行 sed '1~2!d' file
5、特殊情况
例如:sed '$d' file 删除最后一行
例如:sed '1d' file 删除第一行
6、其他:
sed 's/.//' a.txt 删除每一行中的第一个字符
sed 's/.//2' a.txt 删除每一行中的第二个字符
sed 's/.//N' a.txt 从文件中第N行开始,删除每行中第N个字符(N>2)
sed 's/.$//' a.txt 删除每一行中的最后一个字符
xxxxxxxxxx
1、打印匹配将任意数字替换成空或者制表符
2、去掉文件1-5行中的数字、冒号、斜杠
3、匹配root关键字的行替换成hello itcast,并保存到test.txt文件中
4、删除vsftpd.conf、smb.conf、main.cf配置文件里所有注释的行及空行(不要直接修改原文件)
5、使用sed命令截取自己的ip地址
6、使用sed命令一次性截取ip地址、广播地址、子网掩码
7、注释掉文件的2-3行和匹配到以root开头或者以ftp开头的行
1、写一个初始化系统的脚本 1)自动修改主机名(如:ip是192.168.0.88,则主机名改为server88.itcast.cc) 2)自动配置可用的yum源 3)自动关闭防火墙和selinux 2、写一个搭建ftp服务的脚本,要求如下: 1)不支持本地用户登录 2) 匿名用户可以上传 新建 删除 3) 匿名用户限速500KBps
xxxxxxxxxx
xxxxxxxxxx
awk [options] 'commands' file(s)
option 部分
-F 定义字段分割符号,默认的分隔符是空格
-v 定义变量并赋值
command 部分:
'范围说明或正则表达式或者{awk命令语句1;awk命令语句2;...}'
'BEGIN{} {} END{}'
行处理前 行处理 行处理后
1、范围说明部分可以是BEGIN、END、逻辑表达式或者为空
2、awk命令语句间用分号间隔
3、引用shell变量需用双引号引起
举例:
awk '/root/' /etc/passwd
awk 'NR==1' /etc/passwd
awk 'NR==1{print $1}' /etc/passwd
xxxxxxxxxx
awk [options] -f scriptfile file(s)
特点:
1、awk脚本是awk命令的清单
2、命令需要用分号间隔
3、#号开头的是注释行
4、#!/bin/awk -f
xxxxxxxxxx
$0 :表示当前所有记录
$1,$2,$3...$n:awk中用该顺序形式表示files中每行以间隔符号分割的各列的不同字段
注:
awk默认以空格符为间隔符号将每行分割为单独的字段,也可以使用awk内置变量FS定义间隔符号
NF 表示当前记录的字段数(列数)
$NF 最后一列
$(NF-1) 倒数第二列
FNR/NR 行号
FILENAME 文件名
"\t" 制表符
"\n" 换行符
"" 打印字符串
FS 定义间隔符
OFS 定义输出字段分隔符
RS 输入记录分割符,默认换行
ORS 输出记录分割符,默认换行
print 打印函数
格式化输出:
print函数
# date |awk '{print "Month: "$2 "\nYear: "$NF}'
# awk -F: '{print "username is: " $1 "\t uid is: "$3}' /etc/passwd
printf函数
# awk -F: '{printf "%-15s %-10s %-15s\n", $1,$2,$3}' /etc/passwd
# awk -F: '{printf "|%15s| %10s| %15s|\n", $1,$2,$3}' /etc/passwd
# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd
%s 字符类型
%d 数值类型
占15字符
- 表示左对齐,默认是右对齐
printf默认不会在行尾自动换行,加\n
xxxxxxxxxx
# awk -F: '{print $1,$3}' /etc/passwd
(1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束
(2)然后,行被:(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始。
(3)awk如何知道用空格来分隔字段的呢? 因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空格
(4)awk打印字段时,将以设置的方法使用print函数打印,awk在打印的字段间加上空格,因为$1,$3之间
有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格
(5)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔
成字段并进行处理。该过程将持续到所有行处理完毕
xxxxxxxxxx
# awk -v NUM=3 -F: '{ print $NUM }' /etc/passwd
# awk -v NUM=3 -F: '{ print NUM }' /etc/passwd
注意:
awk中调用定义的变量不需要加$
xxxxxxxxxx
关键字:
BEGIN:表示在程序开始前执行
END :表示所有文件处理完后执行
示例:
1. 打印最后一列和倒数第二列(登录shell和家目录)
2. 打印/etc/passwd里的用户名、家目录及登录shell
u_name h_dir shell
***************************
***************************
3. 计算1~10的和
awk -v sum=0 '{sum += $i}END{print sum}'
4. 打印1-10的奇数和
xxxxxxxxxx
== (等于)
!= (不等于)
> (大于)
< (小于)
>= (大于等于)
<= (小于等于)
~ (匹配于)
!~ (不匹配)
! (非)
&& (与)
|| (或)
xxxxxxxxxx
# awk '/root/{print $1}' passwd 使用普通字符定位
# awk '$0 ~ /^root/ {print $1}' passwd 使用正则表达式定位
注意:正则需要用"/xx/"包住
从第一行开始匹配到以lp开头行
awk -F: 'NR==1,/^lp/{print $0 }' passwd
从第一行到第5行
awk -F: 'NR==1,NR==5{print $0 }' passwd
从以lp开头的行匹配到第10行
awk -F: '/^lp/,NR==10 {print $0 }' passwd
从以root开头的行匹配到以lp开头的行
awk -F: '/^root/,/^lp/{print $0}' passwd
打印以root开头或者以lp开头的行
awk -F: '/^root/ || /^lp/{print $0}' passwd
awk -F: '/^root/;/^lp/{print $0}' passwd
显示5-10行
awk -F':' 'NR>=5 && NR<=10 {print $0}' /etc/passwd
awk -F: 'NR<10 && NR>5 {print $0}' passwd
打印IP地址
# ifconfig eth0|awk 'NR>1 {print $2}'|awk -F':' 'NR<2 {print $2}'
# ifconfig eth0|grep Bcast|awk -F':' '{print $2}'|awk '{print $1}'
# ifconfig eth0|grep Bcast|awk '{print $2}'|awk -F: '{print $2}'
# ifconfig eth0|awk NR==2|awk -F '[ :]+' '{print $4RS$6RS$8}'
# ifconfig eth0|awk "-F[ :]+" '/inet addr:/{print $4}'
xxxxxxxxxx
1、显示可以登录操作系统的用户所有信息 //从第7列匹配以bash结尾,输出整行(当前行所有的列)
2、显示可以登录系统的用户名
3、打印出系统中普通用户的UID和用户名如下显示:
UID USERNAME
500 user1
501 user2
511 u10
521 mial01
522 mail01
523 mail02
524 zhangsan
525 lisi
526 wanger
4、以数字开头
5、以任意大小写字母开头
xxxxxxxxxx
if语句:
if [ xxx ];then
xxx
fi
格式:
{if(表达式){语句;语句;...}}
if...else语句:
if [ xxx ];then
xxxxx
else
xxx
fi
格式:
{if(表达式){语句;语句;...}else{语句;语句;...}}
if...else if...else语句:
if [xxxx];then
xxxx
elif [xxx];then
xxx
....
else
...
fi
格式:
{if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}
awk -F: '{if($3==0){i++} else if($3>=500){k++} else{j++}} END{print i; print k; print j}' /etc/passwd
awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd
xxxxxxxxxx
while:
# i=1;while (( $i <=5 ));do echo $i;let i++;done
# awk 'BEGIN{i=1; while(i<=10){print i; i++}}' //打印1-10
# awk -F: '{i=1; while(i<=10) {print $0;i++}}' /etc/passwd //将每行打印10次
for:
# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' //C风格for
1
2
3
4
5
# awk -F: '{for(i=1;i<=10;i++) print $0}' /etc/passwd //将每行打印10次
for
打印1~5
# awk 'BEGIN{for(i=1;i<=5;i++) print i}'
1
2
3
4
5
打印1~10中的奇数
# awk 'BEGIN{for(i=1;i<=10;i=i+2) print i}'
1
3
5
7
9
while
打印1~5
# awk 'BEGIN {i=1;while(i<=5) {print i;i++}}'
打印1~10中的奇数
# awk 'BEGIN {i=1;while(i<=10) {print i;i+=2}}'
1
3
5
7
9
# awk 'BEGIN{for(y=1;y<=5;y++){for(x=1;x<=y;x++)printf x;print}}'
1
12
123
1234
12345
尝试用三种方法打印99口诀表:
# awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i){printf j"*"i"="i*j"\t";j++};print}}'
# awk 'BEGIN{i=1;while(i<=9){for(j=1;j<=i;j++){printf j"*"i"="j*i"\t"}print;i++ }}'
# awk 'BEGIN{for(i=1;i<=9;i++){j=1;while(j<=i){printf j"*"i"="i*j"\t";j++};print}}'
循环的控制:
break 条件满足的时候中断循环
continue 条件满足的时候跳过循环
# awk 'BEGIN{for(i=1;i<=5;i++){if(i==3) break;print i}}'
1
2
# awk 'BEGIN{for(i=1;i<=5;i++){if(i==3) continue;print i}}'
1
2
4
5
# awk 'BEGIN{i=1;while(i<=5){if(i==3) break;print i;i++}}'
1
2
# awk 'BEGIN{i=0;while(i<5){i++;if(i==3) continue;print i}}'
1
2
4
5
xxxxxxxxxx
+ - * / %(模) ^(幂2^3)
可以在模式中执行计算,awk都将按浮点数方式执行算术运算
# awk 'BEGIN{print 1+1}'
# awk 'BEGIN{print 1**1}'
# awk 'BEGIN{print 2**3}'
# awk 'BEGIN{print 2/3}'
####6. 统计案例:
xxxxxxxxxx
1. 统计/etc/passwd 中各种类型shell的数量
# awk -F: '{shells[$NF]++};END{for (i in shells){print i,shells[i]}}' /etc/passwd
2. 网站访问状态统计 <当前时实状态 netstat>
# ss -antp|grep 80|awk '{states[$1]++};END{for(i in states){print i,states[i]}}'
TIME_WAIT 578
ESTABLISHED 1
LISTEN 1
# ss -an |grep :80 |awk '{states[$2]++} END{for(i in states){print i,states[i]}}'
LISTEN 1
ESTAB 5
TIME-WAIT 25
# ss -an |grep :80 |awk '{states[$2]++} END{for(i in states){print i,states[i]}}' |sort -k2 -rn
TIME-WAIT 18
ESTAB 8
LISTEN 1
3. 统计当前访问的每个IP的数量 <当前时实状态 netstat,ss>
# netstat -ant |grep :80 |awk -F: '{ip_count[$8]++} END{for(i in ip_count){print i,ip_count[i]} }' |sort
# ss -an |grep :80 |awk -F":" '!/LISTEN/{ip_count[$(NF-1)]++} END{for(i in ip_count){print i,ip_count[i]}}' |sort -k2 -rn |head
4. 统计Apache/Nginx日志中某一天的PV量 <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |wc -l
14519
5. 统计Apache/Nginx日志中某一天不同IP的访问量 <统计日志>
# grep '27/Jul/2017' mysqladmin.cc-access_log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head
# grep '07/Aug/2017' access.log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |awk '$2>100' |sort -k2 -rn
作业1: 1、写一个自动检测磁盘使用率的脚本,当磁盘使用空间达到90%以上时,需要发送邮件给相关人员 2、写一个脚本监控系统内存和交换分区使用情况
xxxxxxxxxx
作业2: 输入一个IP地址,使用脚本判断其合法性: 必须符合ip地址规范,第1、4位不能以0开头,不能大于255不能小于0
xxxxxxxxxx