Bootstrap

linux系统——shell编程文本处理三剑客

linux系统——shell编程文本处理三剑客

#6 - 文本处理三剑客:

  • grep
  • sed
  • awk

- grep —— 过滤,查找文本中的内容:

  • 分类:
    1,grep
    2,egrep —— 支持正则表达式
    3,fgrep —— 就不支持正则表达式
  • 参数:
    1,grep -q —— 静默,查找到也没有输出
    2,grep -v —— 取反,输出匹配到的以外的内容
    3,grep -R —— 可以查目录下的文件
    3,grep -o —— 只输出匹配到的关键字
    4,grep -B2 —— 输出匹配到的那行的前两行
    5,grep -A2 —— 输出后两行
    6,grep -C2 —— 输出前后两行
    7,egrep -l —— 只输出文件名
    8,egrep -n —— 带行号输出
  • 示例:
egrep 'nw'  abc.txt   		\\abc中查找nw
egrep 'nw'  a*.txt			\\a开头的文件中查找nw
egrep '^n'  abc.txt			\\abc中查找n开头的
egrep '4$'  abc.txt			\\abc中查找4结尾的
egrep tb ac  abc.txxt		\\在ac,abc两个文件中查找tb
egrep 'tb ac'  abc.txt		\\在abc文件中查找tb和ac
egrep '5\..'  abc.txt		\\在abc中查找5.+任一字符
egrep '^[we]'  abc.txt		\\在abc中查找w或e开头的
egrep 'ss*'  abc.txt		\\在abc中查找1-多个s连接的
egrep '3+'  abc.txt			\\在abc中查找1-多个3连接的
egrep '2\.?[0-9]' abc.txt	\\在abc中查找2 + 0-多个点 + 0-9任一数字
egrep 's(h|u)' abc.txt		\\在abc中找sh或su
egrep 'sh|u' abc.txt 		\\在abc中找sh或u

- sed —— 流编辑器,免交互:

  • 格式:
    sed 选项 命令 文件 (多是用这个)
    sed 选项 -f 脚本 文件

  • sed和正则:
    sed -r -r选项支持正则表达式
    sed -i 操作写入文件

  • 命令:
    1,删除:d —— delete
    2,替换:s
    3,读文件:r —— read
    4,写文件:w —— write
    5,追加:a —— after(加到匹配行之后)
    6,插入:i —— insert(插到匹配行之前)
    7,替换整行:c —— change
    8,获取下一行:n —— next(多和其他命令组合使用)
    9,反向选择:!—— 取反
    10,多重编辑 e —— 多条命令组合时 加-e
    11,& —— 找到什么调用什么

  • 示例:

1,删除:d

sed  -r  '/root/d'  passwd			\\删除匹配到root的行
sed  -r  '3d'  passwd		\\删除第三行
sed  -r  '3{d}'  passwd		\\删除第三行
sed  -r  '3{d;}'  passwd	\\删除第三行后执行其他操作
sed  -r  '3,$ d'  passwd	\\删除第三到最后行
sed  -r  '$ d'  passwd		\\删除最后一行

2,替换:s

sed  -r  's/root/aofa/'   passwd		\\匹配到每行第一个root替换成aofa
sed  -r  's/root/aofa/g'   passwd		\\全局替换
sed  -r  's/[0-9][0-9]$/&.5/g'  passwd	\\全局替换,结尾两个数字替换成这两个数字加.5

3,读文件:r

sed  -r '$r  1.txt'  passwd			\\最后一行增加1.txt文件内容
sed  -r '/root/r 1.txt'  passwd		\\匹配到root后在那行后增加1.txt内容

4,写文件:w

sed  -r  'w  111.txt'  passwd			\\passwd文件内容全部写到111
sed  -r  '/root/w  111.txt'  passwd		\\匹配到root后将那行写到111
sed  -r  '1,5w 111.txt'  passwd			\\将passwd文件1-5行写到111

5,追加:a

sed  -r  'a123'  passwd				\\在每一行后加上123
sed  -r  '2a123'  passwd			\\在第二行后加上123

sed  -r  '2a  111\
>222\
>333' passwd				\\在第二行后增加三行,\是转意回车换行

6,插入:i

sed  -r  '2iaaa'  passwd		\\在第二行前增加一行aaa

sed  -r  '2i  aaa\
>bbb\
>ccc'  passwd			\\在第二行前增加三行

7,替换整行:c

sed  -r  '2caaaaaa'   \\第二行整行替换成aaaaaa

sed  -r  '2c  aaa\
>bbb\
>ccc'  passwd			\\第二行替换成三行

8,获取下一行:n

sed  -r  '/root/{n;d}'  passwd		\\匹配到root后删除root行的下一行
sed  -r  '/root/{n;s/bin/ding/g}'  passwd	\\匹配到root后,将下一行的bin换成ding

9,反向选择:!

反向选择,选择的是命令作用范围

sed  -r '2,$d'  passwd		\\删除第二行到最后
sed  -r '2,$!d'  passwd		\\删除开始到第一行

10,多重编辑:e

sed -r -e '1,3d' -e '4s/adm/adming' passwd		
\\同时进行多个操作,先删除1-3行,再将原第四行的adm换成adming

- awk —— 对文本的列操作(切片):

  • 语法:
    awk [options] ‘commands’ filename
    [options] :
    例如-F —— 定义切割符

    commands:
    BEGIN{} —— 行处理前
    {} ——— 行处理时
    END{} —— 行处理后

  • 内部变量:

1,FS —— 输入字段分隔符(默认空格)

awk -F: '{print $1, $3}' /etc/passwd | head -1
root 0
或
awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd | head -1
root x 0
或
awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd | head -1
root 0

2,OFS —— 输出字段分隔符(默认空格)

awk -F: '{print $1,$2,$3,$4}' /etc/passwd | head -1
root x 0 0

awk -F: 'BEGIN{FS=":";OFS="+++"}{print $1,$2,$3,$4}' /etc/passwd | head -1
root+++x+++0+++0

3,RS —— 输入记录(行)分隔符(默认换行符)

awk  '{print $0}' a.txt 
111 222 333 444 555:666:777

awk  'BEGIN{RS="   "}{print $0}' a.txt 
111
222
333
444
555:666:777

4,ORS —— 输出记录(行)分隔符(默认换行符)
5,NR —— 多文件汇总编号

awk -F: '{print NR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
2 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
3 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

6,FNR —— 多文件独立编号

awk -F: '{print FNR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

7,NF —— 字段总数(文件有几列NF,值就是几)

awk -F: '{print NF, $0}'  /etc/passwd
7 root:x:0:0:root:/root:/bin/bash
7 bin:x:1:1:bin:/bin:/sbin/nologin
7 daemon:x:2:2:daemon:/sbin:/sbin/nologin

awk -F: '{print NF, $NF}'  /etc/passwd
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
  • 格式化输出:print 函数
date |awk '{print "Month: " $2 "\nYear: " $1}'
Month: 11月
Year: 2017年

awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd | head -1
username is: root	 uid is: 0

awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd  | head -1
	username and uid: root 0!
  • 模式(正则表达式)及动作:

1,字符串比较:

awk    '/^root/'     /etc/passwd		
awk '$0 ~ /^root/' /etc/passwd			\\~ 像,全局匹配开头像root,输出那行
awk '$0!~/^root/' /etc/passwd
awk -F: '$1 ~ /^root/' /etc/passwd		\\:为分隔符,匹配开头像root,输出整行

2,数值比较:

关系运算:

awk -F: '$3 == 0' /etc/passwd 	 \\匹配第三列等于0,输出那行
awk -F: '$3 == 1' /etc/passwd 	
awk -F: '$3 < 10' /etc/passwd		\\匹配第三列小于10,输出那些行

== 也可以用于字符串判断
awk -F: '$7 == "/bin/bash"' /etc/passwd	
awk -F: '$1 == "alice"' /etc/passwd		\\匹配第一列是alice,输出那行

逻辑运算:

awk -F: '$3 * 10 > 500' /etc/passwd 	
\\匹配第三列的值*10后大于500的列,输出那些列的行

3,多条件:

逻辑操作符:

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 '/从哪里/,/到哪里/' filename
示例:
awk -F: '/adm/,/lpd/' /etc/passwd
从adm到ldp,显示出来,注意避免匹配重复的字段。
  • awk 脚本编程:

1,awk调用变量:

自定义内部变量 -v

awk -v user=root -F: '$1 == user' /etc/passwd
-v定义变量

外部变量 " "

[root@localhost ~]# heihei=shutdown
[root@localhost ~]# echo $heihei
shutdown
[root@localhost ~]# awk  -F:  '$1 ~ "'"$heihei"'"  '     passwd
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown7
注意使用单引号时,内部需要用双引转义

2,条件及判断:

if 单分支:

格式:
{if(表达式){语句;语句;...}}
需求:
如果$3是0,就说他是管理员
示例:
awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd

if 双分支:

格式:
{if(表达式){语句;语句;...}else{语句;语句;...}}
需求:
统计管理员和系统用户数量
示例:
awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd

if 多分支:

句式:
1,{if(表达式1){语句;语句;...}else if(表达式2){语句;语句;...}else if(表达式3){语句;语句;...}else{语句;语句;...}}
2,if (条件){动作}elseif(条件){动作}else{动作}
3,if(){}else if  (){}else if(){}else{}

示例一:
需求:显示出三种用户的信息
管理员:管理员ID为0
内置用户:用户ID<1000
普通用户: 用户ID>999
awk -F:  '{if($3==0){print $1," is admin "}else if ($3>999){print $1," is user"}else {print $1, " is sofo user"}}'  /etc/passwd

示例二:
需求:统计出三种用户的数量
管理员数量:管理员ID为0
内置用户数量:用户ID<1000
普通用户数量: 用户ID>999
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
;