实例妙解Sed和Awk的秘密笔记
课程地址:http://www.imooc.com/learn/819
课程教师:annieose
正则 课程介绍 Linux工程师面对的问题
面对一堆文本要分析?
面对乱乱的数据要处理?
面对长长的服务器日志找报错?
sed和awk应用场景
例如:在服务器日志fresh.log中,找到所有报错的日期
1 sed -n '/Error/p' fresh.log | awk '{print $1}'
Linux三大利器
grep:查找 |
sed:行编辑器 | 一行指令,轻松搞定
awk:文本处理工具 |
学习目标
掌握sed/awk常用处理方法
得心应手使用工具
提高效率,事半功倍
正则表达式 主要内容
正则表达式的应用与学习方法
正则中的字符/字符串
正则中的表达式
正则表达式目标
查找 |
取出 | 符合条件的某个字符或字符串
匹配 |
正则单字符的表示方式 字符 ==》 特定字符、范围内字符、任意字符 ==》 组合
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 特定字符:某个具体的字符。例如:'a','1' grep 'a' passwd grep '1' passwd 范围内字符:单个字符[] 数字字符:[0-9],[259] grep [0-9] passwd grep [259] passwd 小写字符:[a-z] grep '[a-z]' passwd 大写字符:[A-Z] grep '[A-Z]' passwd 扩大范围举例: grep '[a-zA-Z]' passwd grep '[,:/_]' passwd 范围内字符:反向字符^ 取反:[^0-9],[^0] 任意字符: 代表任何一个字符:'.' grep '.' passwd 注意与[.]和\.的区别 grep '[.]' passwd 代表小数点,而不是任意字符 grep '\.' passwd 代表小数点,而不是任意字符
正则其他符号的表示方式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 边界字符:头尾字符 ^:^root 注意与[^]的区别 grep '^root' passwd $:bash$ grep 'bash$' passwd 空行的表示:^$ grep '^$' passwd 元字符(代表普通字符或特殊字符) \w:匹配任何字类字符,包括下划线([A-Za-z0-9]) \W:匹配任何非字类字符,([^A-Za-z0-9]) grep '\w' passwd grep '\W' passwd \b:代表单词的分隔 grep '\bx\b' passwd
正则组合-重复字符表示 1 2 3 4 字符串 'root' '1000' 'm..c' grep 'm..c' passwd (以m开头c结尾,长度为4的字符串) grep '[A-Z][a-z]' passwd (大写字符与小写字符放在一起的字符串组合) grep '\b[0-9][0-9]\b' passwd (两位数字的组合)
字符串 ==》 重复 + 逻辑 ==》 组合表达式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 重复: *:零次或多次匹配前面的字符或子表达式 +:一次或多次匹配前面的字符或子表达式 ?:零次或一次匹配前面的字符或子表达式 [root@cephL ~]# cat test.txt sesesese se seeeeeeeee eeeeee soooooooo +se+se+ [root@cephL ~]# grep 'se*' test.txt sesesese se seeeeeeeee soooooooo +se+se+ [root@cephL ~]# grep 'se\+' test.txt sesesese se seeeeeeeee +se+se+ [root@cephL ~]# grep 'se\?' test.txt sesesese se seeeeeeeee soooooooo +se+se+ [root@cephL ~]# grep '\(se\)\+' test.txt sesesese se seeeeeeeee +se+se+ 重复特定次数:{n,m} *:{0,} +:{1,} ?:{0,1} [root@cephL ~]# grep '\b[0-9]\{2,3\}\b' passwd (截取2位或3位数字)
正则组合-逻辑符合表示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 任意字符串的表示:.* 例如:^r.* m.*c 注意与m..c区别 grep '^r.*' passwd grep 'm.*c' passwd grep 'm..c' passwd grep '\bm.*c\b' passwd grep '\bm[a-z]*c\b' passwd 逻辑的表示: |:'/bin\(false\|true\)' grep 'bin/\(bash\|nologin\)' passwd (或者包含bash,或者包含nologin) 正则表达式字符组合小结: 重复的表示:* + ? {,} 逻辑的表示:|
正则-案例演 1 2 3 4 5 6 7 8 9 案例一 匹配4-10位qq号 grep '^[0-9]\{4,10\}$' qq.txt 案例二 匹配15位或18位身份证号(支持带X的) grep '^[1-9]\([0-9]\{13\}\|[0-9]\{16\}\)[0-9xX]$' qq.txt 案例三 匹配密码(由数字、26个字母和下划线组成) grep '^\w\+$' qq.txt
正则总结
巧妙破解sed 主要内容和原理介绍 sed工具用途
sed是如何进行文本处理的? 我们称sed是一个流处理编辑器
实际的处理流程是行处理
sed一次处理一行内容
sed不改变文件内容(除非重定向)
sed应用的基本格式介绍 正则选定文本 ==》 sed进行处理
1 2 3 4 5 6 7 使用sed格式: 命令行格式 `sed [options] 'command' file(s)` `options: -e ; -n` `command: 行定位(正则)+ sed命令(操作)` 脚本格式 `sed -f scriptfile file(s)`
使用sed举例
1 2 sed -n '/root/p' sed -e '10,20d' -e 's/false/true/g'
sed基本操作命令-p命令 基本操作命令(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 -p(打印相关的行)与-n配合使用 sed -n 'p' passwd 定位一行:x;/pattern/ (x代表行号) sed -n '10p' passwd (打印第10行) nl passwd | sed -n '10p' (nl打印行号) sed -n '/root/p' passwd (打印) 定位几行:x,y;/pattern/,x; (x,y代表行号) /pattern1/,/pattern2/; x,y! (取反) nl passwd | sed -n '10,20p' (打印10行到20行) nl passwd | sed -n '/operator/,/games/p' nl passwd | sed -n '10!p' (不选择第10行) nl passwd | sed -n '10,20!p' (不选择10行到20行) 定位间隔几行:first~step nl passwd | sed -n '1~2p' (从第1行开始,间隔2-1行,再打印)
基本操作命令(2)
1 2 3 4 5 6 7 8 9 10 11 -a (新增行)/ i(插入行) -c (替代行) -d(删除行) nl passwd | sed '5a ===========' (第5行和第6行之间增加分隔符===========) nl passwd | sed '1,5a===========' (第1行和第5行之间,每一行都增加分隔符===========) nl passwd | sed '5i===========' (第5行之前插入分隔符===========) nl passwd | sed '1,5i===========' (第1行和第5行之前,每一行都插入分隔符===========) nl passwd | sed '40c 123123' (将40行替换成123123) nl passwd | sed '35,40c 123123' (将35行到40行替换成123123,35行以后的内容就没有了,只有123123这一行,并不是每一行进行替换,而是对这些行做一个整体的替换) nl passwd | sed '/mooc/d' (删除mooc所在行) sed不会改变源文件的内容,如果要保存结果需要重定向
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 案例一:优化服务器的配置 在ssh的配置文件加入相应文本: " Port 52113 PermitRootLogin no PermitEmptyPasswords no " sed '$a \ port\ 52113 \n permitroologin no' sshd_config (空格需要\转义) 案例二:文本处理 删除文本中空行 sed '/^$/d' sshd_config (空行用正则/^$/表示) 案例三:服务器日志处理 服务器log中找出error报错 sed -n '/Error/p'
基本操作命令(3)
1 2 3 4 5 6 7 8 9 10 11 -s(替换):分隔符/,#等 sed 's/nologin/l/' passwd (nologin替换为l) -g(全局):替换标志 sed 's/:/%/' passwd (只是把每一行的第一个':'替换为'%') sed 's/:/%/g' passwd (所有的':'都被替换为'%') 案例四:数据筛选 获取enp0s8的ip ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet//' (centos7) ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet.*r://' (Ubuntu上有:) ifconfig enp0s8 | sed -n '/inet /p' | sed 's/inet//' | sed 's/n.*$//'
高级操作命令(1)
1 2 -{}:多个sed命令,用;分开 nl passwd | sed '{20,30d;s/nologin/login/}' (先删除20行到30行,然后剩下的行nologin替换成login)
高级操作命令(2)
1 2 3 4 5 -n:读取下一个输入行(用下一个命令处理) nl passwd | sed -n '{n;p}' (你会发现跳行,输出2、4、6、8行。执行过程是sed读入一行后,接着n又读入下一行。输出偶数行) nl passwd | sed -n '2~2p' (输出偶数行) nl passwd | sed -n '{p;n}' (输出奇数行) nl passwd | sed -n '1~2p' (输出奇数行,与上一条命令相等)
高级操作命令(3)
1 2 3 4 5 -&:替换固定字符串 sed 's/^[a-z_-]\+/& /' passwd (用户名后面加上空格) root:x:0:0:root:/root:/bin/bash (源字符串) root :x:0:0:root:/root:/bin/bash (替换后字符串) 如果替换的字符串与源字符串有重复串,可以用&。类似于在源字符串后追加
案例:
1 2 3 4 5 6 7 8 9 10 11 12 案例一:大小写转换 将用户名的首字母转换为大写/小写 (元字符\u \l \U \L:转换为大写/小写字符,小写的\u和\l是对首字母的转换,大写的\U和\L是对一串字符的转换) sed 's/^[a-z_-]\+/\u&/' passwd 案例二:大小写转换 将文件夹下的.txt文件名转换为大写 ls *.txt | sed 's/^\w\+/\U&/' 案例三:数据筛选 获取passwd中USER、UID和GID sed 's/\(^[a-z_-]\+\):x:\([0-9]\+\):\([0-9]\+\):.*$/USER:\1 UID:\2 GID:\3/' passwd
高级操作命令(4)
1 2 3 4 -\( \):替换某种(部分)字符串(\1,\2) 案例二:数据筛选 "获取eth0的ip" ifconfig enp0s9 | sed -n '/inet /p' | sed 's/inet \([0-9.]\+\) .*$/\1/' (centos 7)
高级操作命令(5)
1 2 3 4 5 -r:复制指定文件插入到匹配行(不改变文件内容只改变输出,如果想改变文件内容需要重定向) -w:复制匹配行拷贝指定文件里(改变目标文件) 用处:源文件和目标文件互相操作。 sed '1r 123.txt' abc.txt (从123.txt中读取内容,插入到abc.txt的第1行后 ) sed '1w abc.txt' 123.txt (从123.txt中读入,写入到abc.txt。1w是指定123.txt中的哪一行写入到abc.txt)
高级操作命令(6)
1 2 3 q:退出sed nl passwd | sed '10q' (执行到第10行就结束) nl passwd | sed '/false/q' (找到第一个false就结束)
awk 主要用途:统计、制表
awk处理方式:awk一次处理一行内容、awk对每行可以切片处理
1 awk '{print $1}' //输出首个单词
使用awk的格式:
1 2 3 4 5 6 7 8 9 10 1、命令行格式: awk [options] 'command' file(s) command: pattern {awk 操作命令} pattern: 正则表达式; 逻辑判断式 command1: pattern {awk 操作命令} 操作命令: 内置函数: print() printf() getline..; 控制指令: if(){...}else{...};while(){...}; 2、脚本格式: awk -f awk-script-file file(s)
awk内置参数应用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 awk 内置变量1 $0:表示整个当前行 $1:每行第一个字段 $2:每行第二个字段 这些字段是怎样划分的呢?我们用分隔符 awk内置参数:分隔符 options:-F field-separator(默认为空格) 例如:awk -F ':' '{print $3}' /etc/passwd [root@cephL]# awk -F ':' '{print $1,$3}' passwd awk -F ':' '{print $1" "$3}' passwd awk -F ':' '{print $1"\t"$3}' passwd awk -F ':' '{print "User:"$1"\t""UID:"$3}' passwd awk内置变量: NR:每行的记录号(行) NF:字段数量变量(列) FILENAME:正在处理的文件名 例如:awk -F ':' 'print FILENAME' passwd
awk内置参数应用案例:
1 2 3 4 5 6 7 8 9 10 11 12 案例一: 显示/etc/passwd每行的行号,每行的列数,对应行的用户名(print,printf) awk -F ':' '{print "Line: "NR,"Col: "NF,"User: "$1}' passwd awk -F ':' '{printf("Line: %3s Col: %s User: %s\n",NR,NF,$1)}' passwd 案例二: 显示/etc/passwd中用户ID大于100的行号和用户名(if...else...) awk -F ':' '{if ($3>100) print "Line: "NR,"User: "$1}' passwd 案例三: 在服务器log中找出'Error'的发生日期 sed '/Error/p' fresh.log | awk '{print $1}' awk '/Error/{print $1}' fresh.log
使用awk——逻辑判断式
1 2 3 4 5 6 7 8 9 10 11 12 13 command: pattern {awk 操作命令} pattern: 正则表达式;逻辑判断式 awk逻辑 ~,!~: 匹配正则表达式 ==,!=,<,>: 判断逻辑表达式 1、第一个字段是'm'开头的 awk -F ':' '$1~/^m.*/{print $1}' passwd 2、第一个字段不是'm'开头的 awk -F ':' '$1!~/^m.*/{print $1}' passwd 3、第三个字段大于100 awk -F ':' '$3>100{print $1,$3}' passwd
使用awk——扩展格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 1、命令行格式: awk [options] 'command' file(s) command2扩展 BEGIN{print "start"} pattern{commands} END{print "end"} awk是以行为操作单位的,BEGIN是在没有读入第一行之间执行的,END是处理完最后一行执行的 案例一: 制表显示/etc/passwd每行的行号,每行的列数,对应行的用户名 awk -F ':' 'BEGIN{print "Line\tCol\tUser"}{print NR"\t"NF"\t"$1}END{print "---"FILENAME"---"}' passwd 案例二: 统计当前文件夹下的文件/文件夹占用的大小 ls -l | awk 'BEGIN{size=0}{size+=$5}END{print "size is "size/1024/1024"M"}' 案例三: 统计显示/etc/passwd的账户总人数 awk -F ':' 'BEGIN{count=0}$1!~/^$/{count++}END{print "count = "count}' passwd 统计显示UID大于100的用户名 awk -F ':' 'BEGIN{count=0}{if ($3 > 100) name[count++]=$1}END{for(i=0;i<count;i++) print i,name[i]}' passwd 案例四: 统计netstat -anp 状态下为LISTEN和CONNECTED的连接数量 netstat -anp | awk '$6~/CONNECTED|LISTEN/{sum[$6]++}END{for(i in sum)print i,sum[i]}'
awk VS sed
1 2 3 4 5 awk和sed都可以处理文本 awk侧重于复杂逻辑处理 sed侧重于正则处理 awk和sed可以共同使用