sed
sed简介
sed 是一种在线的、非交互式的编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
Sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
语法:
sed 参数【-r 支持扩展正则 -i 直接修改文件 -n -e -f】 command【p d a i s c】 文件
注意:command:会用到正则表达式 如果遇到扩展正则表达式,一定要加-r或者是对扩展正则符号转译
sed常用参数:
-n 静默输出(不打印默认输出) sed -n '1p' a.txt 想显示第几行就显示第几行
-e 给予sed多个命令的时候需要-e选项
#sed -e 's/root/haha/g' -e 's/bash/wwwww/g' passwd > passwd.bak
如果不用-e选项也可以用分号“;”把多个命令隔开。
#sed 's/haha/ro/g ; s/wwwww/kkkk/g' passwd | less 这个是-e的结果
-i -i后面没有扩展名的话直接修改文件,如果有扩展名备份源文件,产生以扩展名结尾的新文件
#sed -iback1 -e 's/root/rottt/g' -e 's/bash/wwwww/g' passwd //选项-i后面没有空格
[root@localhost 桌面]# ls
manifest.txt passwdback1
-f 当有多个要编辑的项目时,可以将编辑命令放进一个脚本里,再使用sed搭配-f选项
[root@localhost 桌面]# cat s.sed
s/bin/a/g
s/ftp/b/g
s/mail/c/g
[root@localhost 桌面]# sed -f s.sed passwd | less
-r 可使用扩展正则
sed常用编辑命令
sed所有命令的使用要放在引号里
p 打印行 1p 输出再打印一遍第一行 1~2 打印奇数 0~2打印偶数
d 删除文本 '1~2d'#删除奇数行 '0~2d'#删除偶数行
#sed '1 d' passwd
#sed '$ d' passwd
#sed '1,3 d' passwd
#sed '1,/^dian/ d' passwd
a 追加文本(后)
#sed '2 a nihao' passwd
#sed '/^dian/ a nihao' passwd
i 前插
# sed -i '1 i nihao' passwd
c 替换 sed '/zhong/ c abc' 将zhong这一行替换成abc
#sed -i '1 c no' passwd
s 替换指定字符,一般格式为s///g
实例:
sed: stream editor(流编辑器)的缩写. 它们最常见的用法是进行文本的替换.
1. sed可以从stdin中读取内容
$ cat filename | sed 's/pattern/replace_string/'
2. 选项-i会使得sed用修改后的数据替换原文件
$ sed -i 's/pattern/replace_string/' filename
3. g标记可以使sed执行全局替换
$ sed 's/pattern/replace_string/g' filename
4. g标记可以使sed匹配第N次以后的字符被替换 #把所有匹配到a的行中第n次及第n次之后出现的a替换成b
$ echo "thisthisthisthis" | sed 's/this/THIS/2g'
5. sed中的分隔符可以替换成别的字符, 因为s标识会认为后面的字符为分隔符
$ sed 's:text:replace_text:'
$ sed 's|text|replace_text|'
6. sed可以利用指令来删除文件中的空行
$ sed '/^$/d' filename
7. 替换指定的字符串或数字
$ cat sed_data.txt
11 abc 111 this 9 file contains 111 11 99 numbers 0000
$ sed -i 's/\b[0-9]\{3\}\b/NUMBER/g' sed_data.txt
$ cat sed_data.txt
11 abc NUMBER this 9 file contains NUMBER 11 99 numbers 0000
8. 由于在使用-i参数时比较危险, 所以我们在使用i参数时在后面加上.bak就会产生一个备份的文件,以防后悔
$ sed -i.bak 's/pattern/replace_string/' filename
9.删除配置文件中 # 号注释的行
[root@localhost ~]# sed -ri '/^#/d' ssh_config
10.给文件行添加注释:
[root@localhost ~]# sed -r '2,5s/^/#/' passwd
给所有行添加注释:
[root@localhost ~]# sed -r 's/^/#/' passwd
11.给文件行添加和取消注释
[root@localhost ~]# sed -ri s/^#baseurl/baseurl/g /etc/yum.repos.d/CentOS-Base.repo
[root@localhost ~]# sed -r s/^mirrorlist/#mirrorlist/g /etc/yum.repos.d/CentOS-Base.repo
awk
awk简介
awk 是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。
awk的处理文本和数据的方式是这样的,它逐行扫描文件,从第一行到最后一行,寻找匹配的特定模式的行,并在这些行上进行你想要的操作。如果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),如果没有指定模式,则所有被操作所指定的行都被处理。
awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩展。
awk语法格式
awk [options] 'commands' filenames
options:
-F:输入字段分隔符,默认的分隔符是空格或制表符(tab键)
command:
awk 'BEGIN{} {} END{} ' filename
处理前的动作 行内容处理的动作 行处理后的动作 文件名
BEGIN{}和END{}是可选项
BEGIN{} 所有文本内容读入之前要执行的命令 可以不需要后面跟文件,因为他是在读入文件之前的操作
{}:主输入循环 读入一行命令执行一次循环
END{}:所有文本都读入完成之后执行的命令 必须要读入文件,因为他是在读入文件之后的操作
例:[root@nfy ~]# awk 'BEGIN{print "==="} {print "ok"} END{print "+++"}' /etc/hosts
#行内容处理前打印===,读完一行内容打印ok,行内容处理完打印+++
===
ok
ok
+++
awk工作原理
# awk 'BEGIN{FS=":"} {print $0}' /etc/passwd|head -1
root:x:0:0:root:/root:/bin/bash
(1)awk使用一行作为输入,并将这一行赋给内部变量$0,每一行也可称为一个记录,以换行符结束
root : x : 0 : 0 : root : /root : /bin/bash
1 2 3 4 5 6 7
(2)然后,行被(默认为空格或制表符)分解成字段(或域),每个字段存储在已编号的变量中,从$1开始,最多达100个字段
(3)awk如何知道用空格来分隔字段的呢? 因为有一个内部变量FS来确定字段分隔符。初始时,FS赋为空格
[root@nfy ~]# awk '{print $1,$2}' /etc/hosts
127.0.0.1 localhost
::1 localhost
(4)awk打印字段时,将以设置的方法使用print函数打印,awk在打印出来的字段间有空格,因为$1,$3之间有一个逗号。逗号比较特殊,它映射为另一个内部变量,称为输出字段分隔符OFS,OFS默认为空格
# awk 'BEGIN{FS=":"} {print $1,$2}' /etc/passwd |head -1
root x
(5)awk输出之后,将从文件中获取另一行,并将其存储在$0中,覆盖原来的内容,然后将新的字符串分隔成字段并进行处理。该过程将持续到所有行处理完毕
记录与字段相关内部变量
可以通过man awk来查看,以下为常用变量
1、$0:表示整行
[root@localhost ~]# awk '{print $0}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
2、NF:统计字段的个数
[root@localhost ~]# awk '{print $0,NF}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 5 #字段个数5
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 5
那么$NF就是最后一列的信息
[root@localhost ~]# awk '{print $0,$NF}' /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 localhost6.localdomain6
3、NR:表示行数(打印记录号)
FNR:可以分开,按不同的文件打印行号。
NR:
[root@localhost ~]# awk '{print NR,$0}' /etc/passwd /etc/hosts
1 root:x:0:0:root:/root:/bin/bash
......
27 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false
28 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
29 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
1-27行是/etc/passwd/文件中的行内容,28-29是/etc/hosts文件中的行内容,NR打印行号是把多个文件的行内容放在一起打印行号
FNR:
[root@localhost ~]# awk '{print FNR,$0}' /etc/passwd /etc/hosts
1 root:x:0:0:root:/root:/bin/bash
......
27 mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/false
1 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
FNR打印完/etc/passwd文件中行内容的行号后重新打印/etc/hosts文件中行内容的行号
4、FS:输入字段分隔符,默认为空格
# awk -F: '/root/{print $1, $3}' /etc/passwd
或者# awk 'BEGIN{FS=":"} /root/{print $1,$3}' /etc/passwd
# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd \t水平制表符
[root@localhost ~]# awk -F'[ :\t]' '/root/{print $1,$2,$3}' /etc/passwd
root x 0
operator x 11
[root@localhost ~]# awk -F':' '/root/{print $1,$2,$3}' /etc/passwd
root x 0
operator x 11
5、OFS:输出字段分隔符,默认为空格
[root@localhost ~]# awk 'BEGIN{OFS="+++"} {print $1,$2}' /etc/hosts 指定以+++连接
127.0.0.1+++localhost
::1+++localhost
[root@localhost ~]# awk '{print $1,$2}' /etc/hosts 默认为空格连接
127.0.0.1 localhost
::1 localhos
6、RS:输入记录分隔符(默认是换行符)
[root@localhost ~]# vim passwd
root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# cat passwd | awk 'BEGIN{RS="bash"} {print $0}'
root:x:0:0:root:/root:/bin/
bin:x:1:1:bin:/bin:/sbin/nologin
7、ORS:输出记录分隔符(默认是换行符)
[root@localhost ~]# vim passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost ~]# cat passwd | awk 'BEGIN{ORS=" "} {print $0}'
root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin
区别:
字段分隔符: FS OFS 默认空格或制表符
记录分隔符: RS ORS 默认换行符
练习
[root@localhost ~]# awk 'BEGIN{ORS=""} {print $0}' /etc/passwd
#将文件每一行合并为一行
[root@localhost ~]# awk 'BEGIN{ORS=" "} {print $0}' /etc/passwd^C
[root@localhost ~]# head -1 /etc/passwd > passwd
[root@localhost ~]# cat passwd
root:x:0:0:root:/root:/bin/bash
[root@localhost ~]# awk 'BEGIN{RS=":"} {print $0}' passwd
root
x
0
0
root
/root
/bin/bash
这还有空行
[root@localhost ~]# awk 'BEGIN{RS=":"} {print $0}' passwd |grep -v '^$' > passwd1
#grep -v 取反,匹配不在''范围的内容
格式化输出
print 和 printf
print 根据 awk 的匹配规则,匹配到需要的数据,然后使用 print 打印出来!
print 在打印字段的时候,需要使用 “,”(逗号) 隔开字段 ,各个字段都会 自动转换成字符串格式,然后根据 自定义的内置变量“OFS”(默认值为 空格) 的值来连接输出的各个字段的字符串!
print 要输出的数据被称之为 “记录”,在print 输出时,会在后面自动加上 输出记录分隔符“ORS” ,它的值默认为换行符 “\n”。
printf
printf 是根据我们自己设定的格式来输出文本。说到输出文本,就会想到另一个常用输出命令:echo。
很清楚的看到,echo 自动给输出的文本进行换行,而 printf 却没有。如果想换行只能结合换行符 “\n”来换行。
常用格式化字符:
%s 字符类型
%d 数值类型
%f 浮点类型
- 表示左对齐,默认是右对齐
%s %f都是格式替代符
%-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中.2指保留2位小数。
awk模式和动作
任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发事件。处理即对数据进行的操作。
如果省略模式部分,动作将时刻保持执行状态。模式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段 BEGIN和END。使用BEGIN语句设置计数和打印头。BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文本开始执行。END语句用来在awk完成文本浏览动作后打印输出文本总数和结尾状态。
模式可以是:正则表达式、匹配操作符、比较表达式、关系运算符、条件表达式、算术运算、逻辑操作符和复合模式、范围模式。
正则表达式
匹配记录(整行):~ 匹配
[root@nfy ~]# awk '/^root/' /etc/passwd 在/etc/passwd文件中匹配以root开头的行
root:x:0:0:root:/root:/bin/bash
[root@nfy ~]# awk '$0 ~ /^root/' /etc/passwd 在/etc/passwd文件中匹配整行以root开头的
root:x:0:0:root:/root:/bin/bash
[root@nfy ~]# awk '!/root/' /etc/passwd 在/etc/passwd文件中匹配行中没有root字段的行
[root@nfy ~]# awk '$0 !~ /^root/' /etc/passwd 在/etc/passwd文件中匹配整行不以root字段的行
匹配字段:匹配操作符(~ !~)
[root@nfy ~]# awk -F: '$1 ~ /^root/' /etc/passwd 匹配第一例以root开头的行
root:x:0:0:root:/root:/bin/bash
[root@nfy ~]# awk -F: '$NF !~ /bash$/' /etc/passwd 匹配最后一列不以bash结尾的行
比较表达式
比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符,用于比较数字与字符串。
关系运算符
# awk -F: '$3 == 0' /etc/passwd 匹配第三列等于0的行
# awk -F: '$3 < 10' /etc/passwd 匹配第三列小于10的行
# awk -F: '$NF == "/bin/bash"' /etc/passwd 匹配最后一列为/bin/bash的行
# awk -F: '$1 == "alice"' /etc/passwd 匹配第一列为alice的行
# awk -F: '$1 ~ /alic/ ' /etc/passwd 匹配第一列中有alice的行
# awk -F: '$1 !~ /alic/ ' /etc/passwd 匹配第一列中没有alice的行
# df -P | grep '/' |awk '$4 > 25000' 查看磁盘使用信息,过滤有/的行,再匹配第四列大于25000的行
条件表达式
# awk -F: '$3>300 {print $0}' /etc/passwd
第三列大于300,打印整行
# awk -F: '{ if($3>300) {print $0} }' /etc/passwd
如果第三列大于300,打印整行
# awk -F: '{ if($3>300) {print $3} else{print $1} }' /etc/passwd
如果第三列大于300,打印第三列,否则打印第一列
算术运算
# awk -F: '$3 * 10 > 500' /etc/passwd 匹配第三列乘以10后大于500的行
# awk -F: '{ if($3*10>500){print $0} }' /etc/passwd 如果第三列乘以10后大于500,打印该行
# awk -F: '{if ($3*10>500){print $3*2}}' /etc/passwd 如果第三列乘以10后大于500,打印第三列乘以2的数值
逻辑操作符和复合模式
&& 逻辑与 a&&b
|| 逻辑或 a||b
! 逻辑非 !a 除了这个以外的
# awk -F: '$1 ~ /root/ && $3<=15' /etc/passwd
匹配第一列中有root的并且第三列小于等于15的行 必须两个条件都满足
# awk -F: '$1 ~ /root/ || $3<=15' /etc/passwd
匹配第一列中有root的或者第三列小于等于15的 满足其中一个条件就算
# awk -F: '!($1 ~ /root/ || $3<=15)' /etc/passwd
匹配除了第一列中有root的或第三列小于等于15的行
小练习
awk示例:
# awk '/west/' datafile 匹配有west的行
# awk '/^north/' datafile 匹配以north开头的行
# awk '$3 ~ /^north/' datafile 匹配第三列以north开头的行
# awk '/^(no|so)/' datafile 匹配以no或者so开头的行
# awk '{print $3,$2}' datafile 打印第三列第二列 (输出字段默认以空格为分隔符)
# awk '{print $3 $2}' datafile 打印第三列第二列,中间没有分隔符
# awk '{print $0}' datafile 打印所有行
# awk '/northeast/{print $3,$2}' datafile 匹配有northeast的行,打印第三列,第二列
# awk '/E/' datafile 匹配行中有E的行
# awk '/^[ns]/{print $1}' datafile 匹配以n或者s开头的行,打印第一列
# awk '$5 ~ /\.[7-9]+/' datafile 匹配第五列中有.数字(该数字在7-9,出现1次或多次)的行
# awk '$2 !~ /E/{print $1,$2}' datafile 匹配第二列中没有E的行,打印第一列第二列
# awk '$3 ~ /^Joel/{print $3 " is a nice boy."}' datafile 匹配第三列以Joel开头的行,打印..
# awk '$8 ~ /[0-9][0-9]$/{print $8}' datafile 匹配第八列以两个数字结尾的行,打印第八列
# awk '$4 ~ /Chin$/{print "The price is $" $8 "."}' datafile 匹配第四列以Chin接吻的行,打印...
# awk '/Tj/{print $0}' datafile 匹配行中有Tj的行,打印这一行
# awk '{print $1}' /etc/passwd 打印第一行
# awk -F: '{print $1}' /etc/passwd 以:为输入字段分隔符,打印第一列
# awk '{print "Number of fields: "NF}' /etc/passwd 打印Number of fields:(NF为字段数)
# awk -F: '{print "Number of fields: "NF}' /etc/passwd 以:为输入字段分隔符,打印..
# awk -F"[ :]" '{print NF}' /etc/passwd 以空格或者:为输入字段分隔符,打印字段数
# awk -F"[ :]+" '{print NF}' /etc/passwd 以多个空格或者多个冒号为输入字段分隔符打印..
# awk '$7 == 5' datafile 匹配第七列等于5的行
# awk '$2 == "CT" {print $1, $2}' datafile 匹配第二列等于CT的行,打印第一列第二列
# awk '$7 != 5' datafile
lab3:
[root@xingdian ~]# cat b.txt
xingdian sheng:is a::good boy!
[root@xingdian ~]# awk '{print NF}' b.txt
4
[root@xingdian ~]# awk -F: '{print NF}' b.txt
4
[root@xingdian ~]# awk -F"[ :]" '{print NF}' b.txt
7
[root@xingdian ~]# awk -F"[ :]+" '{print NF}' b.txt
6
# awk '$7 < 5 {print $4, $7}' datafile #{if($7<5){print $4,$7}}
# awk '$6 > 9 {print $1,$6}' datafile
# awk '$8 <= 17 {print $8}' datafile
# awk '$8 >= 17 {print $8}' datafile
# awk '$8 > 10 && $8 < 17' datafile
# awk '$2 == "NW" || $1 ~ /south/ {print $1, $2}' datafile
# awk '!($8 == 13){print $8}' datafile #$8 != 13
# awk '/southem/{print $5 + 10}' datafile
# awk '/southem/{print $8 + 10}' datafile
# awk '/southem/{print $5 + 10.56}' datafile
# awk '/southem/{print $8 - 10}' datafile 匹配行中有southem的行,打印第八列减10的的值
# awk '/southem/{print $8 / 2 }' datafile 匹配行中有southem的行,打印第八列除以2的的值
# awk '/southem/{print $8 / 3 }' datafile 匹配行中有southem的行,打印第八列除以3的的值
# awk '/southem/{print $8 * 2 }' datafile 匹配行中有southem的行,打印第八列乘2的值
awk结合if判断
if语句
格式:{if(表达式){语句;语句;}}
awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd //统计系统用户数
if...else语句
格式:{if(表达式){语句;语句} else{语句;语句}}
awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
awk -F: '{if($3==0) {count++} else{i++} }' /etc/passwd
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd
if...else if...else语句
格式:{if(表达式1){语句;语句} else if(表达式2){语句;语句} else if(表达式3){语句;语句}else{语句;语句}}
awk -F: '{if($3==0){i++} else if($3>999){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
awk结合循环
while循环
格式:awk 'BEGIN{} {while(条件表达式){语句}} END{}' begin和end是可选项
[root@xingdian ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }'
[root@xingdian ~]# awk -F: '/^root/{i=1; while(i<=7){print $i; i++}}' passwd
[root@xingdian ~]# awk '{i=1; while(i<=NF){print $i; i++}}' /etc/hosts
[root@xingdian ~]# awk -F: '{i=1; while(i<=10) {print $0; i++}}' /etc/passwd //将每行打印10次
[root@nfy ~]# awk -F: '{i=1; while(i<=10) {print $i; i++}}' passwd
root
x
0
0
root
/root
/bin/bash
空行
空行
空行 之所以有三行空行是因为awk将文件中每一列内容打印完之后while循环并没有结束,又读了三个空格,直到i大于10才结束循环
for循环
语句:awk 'BEGIN{} {for(条件表达式){语句}} END{}'
[root@xingdian ~]# awk 'BEGIN{for(i=1;i<=5;i++){print i} }' //C风格for
1
2
3
4
5
[root@xingdian ~]# awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd
//将每行打印10次
[root@xingdian ~]# awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
//分别打印每行的每列
root
x
0
0
root
/root
/bin/bash
bin
x
1
1
bin
/bin
/sbin/nologin
awk结合数组
数组遍历
按元素个数遍历
# awk -F: '{username[x++]=$1} END{for(i=0;i<x;i++) print i,username[i]}' /etc/passwd
0 root
1 bin
2 daemon x++先赋值再运算,从零开始
3 adm
4 lp
5 sync
6 shutdown
7 halt
8 mail
9 operator
10 games
11 ftp
12 nobody
13 systemd-network
14 dbus
15 polkitd
16 abrt
17 tss
18 postfix
19 chrony
20 sshd
21 nginx
22 apache
23 rpc
24 rpcuser
25 nfsnobody
26 mysql
# awk -F: '{username[++x]=$1} END{for(i=1;i<=x;i++) print i,username[i]}' /etc/passwd
1 root
2 bin
3 daemon ++x先运算再赋值,从1开始
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-network
15 dbus
16 polkitd
17 abrt
18 tss
19 postfix
20 chrony
21 sshd
22 nginx
23 apache
24 rpc
25 rpcuser
26 nfsnobody
27 mysql
按索引遍历
# awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
# awk -F: '{username[++x]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
注:变量i是索引
awk外部变量
awk使用外部变量:
sub 是awk中的内部函数,相当于查找替换 gusb
方法一:在双引号的情况下使用
[root@xingdian ~]# var="bash"
[root@xingdian ~]# echo "unix script" |awk "gsub(/unix/,\"$var\")" 将引号转义
bash script
方法二:在单引号的情况下使用
[root@xingdian ~]# var="bash"
[root@xingdian ~]# echo "unix script" |awk 'gsub(/unix/,"'"$var"'")' 双引+单引+双引
bash script
[root@xingdian ~]# i=10
[root@xingdian ~]# df -h |awk '{ if(int($5)>"'$i'"){print $6":"$5} }' 双引+单引
/:21%
/boot:15%
awk -v
[root@xingdian ~]# echo "unix script" |awk -v var="bash" 'gsub(/unix/,var)'
bash script
[root@xingdian ~]# awk -v user=root -F: '$1 == user' /etc/passwd
root:x:0:0:root:/root:/bin/bash
作业
awk基础作业:
1.获取系统中所有网卡的IP地址,图见群,输出要求:例如:IP地址:172.0.0.1 网卡:lo
ip a|grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'|awk '{print "IP地址:"$2,"网卡:"$NF}'
2.获取内存的使用情况,需要获取的有:总量,使用量,空闲量
简单的:free -m|awk 'NR==2''{print "总量:"$2,"使用量:"$3,"空闲量:"$4}'
复杂点:free -m|awk '{if(NR>1 && NR<3){print "总量:"$2,"使用量:"$3,"空闲量:"$4}}'
2.1如果空闲量小于100M时,打印结果,如果不小于100M,打印结果为空
free -m|awk 'NR==2 {if($4<100){print $4} else{print " "}}'
3.获取当前系统系统中所有挂载点的使用量,输出要求:例如:/=50
df -TH|grep "/"|awk 'BEGIN{OFS="="}{print $NF,$4}'
4.打印出/etc/hosts文件的最后一个字段(输入字段分隔符采用默认)
awk '{print $NF}' /etc/hosts
5.打印指定目录下的目录名,例如获取/目录下所有的目录名
ll /|awk '/^d/{print $NF}'
5.1利用脚本能够实现手动输入目录获取到该目录下目录名
read -p "请输入目录名,假维斯将列出该目录下的目录:" dir
ls -l $dir|awk '/^d/{print $NF}'
6.获取当前系统中arp表中IP地址和MAC地址的对应关系,输出要求:IP地址:10.0.0.125 MAC地址:00:0c:29:4c:37:60
arp -n|grep -E "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"|awk '{print "IP地址:"$1,"MAC地址:"$3}'
arp -n|awk '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/{print "IP地址:"$1,"MAC地址:"$3}'
awk高级作业:
1.获取当前系统中不同shell的数量,输入要求:shell名称:/bin/bash 数量:20
awk -F: '{a[$NF]++} END{for(i in a){print "shell名称:"i,"数量:"a[i]}}' /etc/passwd
2.统计当前服务器不同IP的访问次数,(UV,文件见群)输出要求:IP地址:10.0.0.10 次数:10000;只要前十
awk '{a[$1]++} END{for(i in a){print "IP地址: "i,"次数: "a[i]}}' access_log |sort -k4 -nr|head
3.统计不同状态码的数量,文件见群
awk '$9 ~ /[0-9]+/{a[$9]++;} END{for(i in a){print i,a[i]}}' access_log
4.统计其中某一天不同IP的访问次数(文件见群,具体哪一天根据文件内容自己决定)
awk '/\[12\/Jan\/2022/{a[$1]++} END{for(i in a){print "ip地址:"i,"次数:"a[i]}}' access_log
5.统计用户名为4个字符的用户,将用户名打印到终端
awk -F: '$1 ~ /^....$/{print $1}' /etc/passwd
6.统计系统中ssh登录成功和ssh登录失败的次数
awk '$11 ~ /[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/{a[$6]++} END{for(i in a){print i,a[i]}}' /var/log/secure
grep
grep: 在文件中全局查找指定的正则表达式,并打印所有包含该表达式的行
egrep: 扩展的egrep,支持更多的正则表达式元字符
fgrep: 固定grep(fixed grep),有时也被称作快速(fast grep),它按字面解释所有的字符(了解)
grep命令格式
grep [选项] PATTERN filename filename ...
# grep 'Tom' /etc/passwd
# grep 'bash shell' /etc/test
找到: grep返回的退出状态为0
没找到: grep返回的退出状态为1
找不到指定文件: grep返回的退出状态为2
grep 程序的输入可以来自标准输入或管道,而不仅仅是文件,例如:
# ps aux |grep 'sshd'
# ll |grep '^d'
# grep 'alice' /etc/passwd /etc/shadow /etc/group
grep使用的元字符
grep: 使用基本元字符集 ^, $, ., *, [], [^], \< \>,\(\),\{\}, \+, \|
egrep(或grep -E): 使用扩展元字符集 ?, +, { }, |, ( )
注:grep也可以使用扩展集中的元字符,仅需要对这些元字符前置一个反斜线
\w 所有字母与数字,称为字符[a-zA-Z0-9] 'l[a-zA-Z0-9]*ve' 'l\w*ve'
\W 所有字母与数字之外的字符,称为非字符 'love[^a-zA-Z0-9]+' 'love\W+'
\b 词边界 '\<love\>' '\blove\b'
示例
grep -E 或 egrep
# egrep 'N\W' datafile
# egrep '^n' datafile
# egrep '4$' datafile
# egrep '5\..' datafile 匹配行中有5.(一个字符) 的行
# egrep '\.5' datafile
# egrep '^[we]' datafile
# egrep '[^0-9]' datafile
# egrep '[A-Z][A-Z] [A-Z]' datafile
# egrep 'ss* ' datafile
# egrep '[a-z]{9}' datafile
# egrep '\<north' datafile
# egrep '\<north\>' datafile
# egrep '\<[a-r].*n\>' datafile
# egrep '^n\w*\W' datafile
# egrep '\bnorth\b' datafile
# egrep '3+' datafile
# egrep '2\.?[0-9]' datafile
# egrep '(no)+' datafile
grep常用参数
-i, --ignore-case 忽略大小写
-l, --files-with-matches 只列出匹配行所在的文件名
-n, --line-number 在每一行前面加上它在文件中的相对行号
-c, --count 显示成功匹配的行数
-s, --no-messages 禁止显示文件不存在或文件不可读的错误信息
-q, --quiet, --silent 静默--quiet, --silent
-v, --invert-match 反向查找,只显示不匹配的行
-R, -r, --recursive 递归针对目录
--color 颜色
-o, --only-matching 只显示匹配的内容
-I 列出匹配行所在的文件名并列出匹配的行
示例
[root@xingdian ~]# grep -R 'ifcfg' /etc 目录
[root@xingdian ~]# egrep 'root' /etc/passwd /etc/shadow /etc/hosts
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/shadow:root:$6$gcO6Vp4t$OX9LmVgpjtur67UQdUYfw7vJW.78.uRXCLIxw4mBk82Z99:7:::
[root@xingdian ~]# egrep -l 'root' /etc/passwd /etc/shadow /etc/hosts
/etc/passwd
/etc/shadow
[root@xingdian ~]# egrep -n 'root' /etc/passwd /etc/shadow /etc/hosts
/etc/passwd:1:root:x:0:0:root:/root:/bin/bash
/etc/passwd:11:operator:x:11:0:operator:/root:/sbin/nologin
/etc/shadow:1:root:$6$gcO6Vp4t$OX9LmVgpjtur67UQdUy8.M78.uRXCLIxw4mBk82ZrNlxyf54
[root@xingdian ~]# egrep -R '54:04:A6:CE:C2:1F' /etc/sysconfig/
[root@xingdian ~]# egrep '^IPADDR' /etc/sysconfig/network-scripts/ifcfg-eth0 |egrep -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
192.168.2.254
[root@xingdian ~]# egrep '^IPADDR' /etc/sysconfig/network-scripts/ifcfg-eth0 |egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}'
192.168.2.254
expect(重要)
在实际工作中我们运行命令、脚本或程序时, 都需要从终端输入某些继续运行的指令,而这些输 入都需要人为的手工进行. 而利用 expect 则可以根据程序的提示, 模拟标准输入提供给程序, 从而实现自动化交互执行,这就是 expect 。
它是一个免费的编程工具, 用来实现自动的交互式任务, 而无需人为干预. 说白了 expect 就是一套用来实现自动交互功能的软件 。
既:通过expect可以实现将交互式的命令变为非交互式执行,不需要人为干预(手动输入)
需要先下载expect服务
yum -y install expect
语法
用法:
1)定义expect脚本执行的shell
#!/usr/bin/expect -----类似于#!/bin/bash
2)spawn
spawn是执行expect之后后执行的内部命令开启一个会话 #功能:用来执行shell的交互命令
3)expect ---相当于捕捉
功能:判断输出结果是否包含某项字符串(相当于捕捉命令的返回的提示)。没有捕捉到则会断开,否则等待一段时间后返回,等待通过timeout设置
4)send
执行交互动作,将交互要执行的命令进行发送给交互指令,命令字符串结尾要加上“\r”,#---相当于回车
5)interact
执行完后保持交互状态,需要等待手动退出交互状态,如果不加这一项,交互完成会自动退出
6)exp_continue
继续执行接下来的操作
7)timeout
返回设置超时时间(秒)
案例
rpm -qa |grep expect
if [ $? -eq 0 ];then
echo "expect 已安装"
else
yum -y install expect
fi
rm -rf /root/.ssh/*
read -p "请输入ip:" ip
read -p "请输入对应密码:" passwd
/usr/bin/expect <<EOF
set timeout 30
spawn ssh-keygen
expect "Enter file in which to save the key (/root/.ssh/id_rsa):"
send "\n"
expect "Enter passphrase (empty for no passphrase):"
send "\n"
expect "Enter same passphrase again:"
send "\n"
spawn ssh-copy-id ${ip}
expect {
"yes/no" { send "yes\n"; exp_continue }
"password:" { send "${passwd}\n"}
}
expect eof
EOF
ssh-add
~