shell-三剑客-6

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

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
~              
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值