文本处理工具与正则表达式
1 文本处理工具VIM
1.1 软件简介
纯文本文件:由ASCII, Unicode 或其它编码的纯文字的文件
文本文件编辑工具:
-
全屏编辑器
nano(字符工具), gedit(图形化工具), vi,vim - 行编辑器:sed
vi——Visual editor,文本编辑器
vim——VIsual editor iMproved ,和vi 使用方法一致,但功能更为强大
1.2 使用 vim 初步
vim分很多种工作模式,操作之前首先明确当前处于哪个模式
首要快捷键:模式之间相互切换
vim 命令格式
vim [OPTION]... FILE...
+# 打开文件后,让光标处于第#行的行首,+默认行尾
+/ PATTERN 让光标处于第一个被PATTERN匹配到的行行首
-b file 二进制方式打开文件
-d file1 file2…比较多个文件,相当于 diff
-m file 只读模式打开文件
-e file 直接进入ex模式,相当于执行ex file
说明:
- 如果该文件存在,文件被打开并显示内容
- 如果该文件不存在,当编辑后第一次存盘时创建它
1.3 三种主要模式和转换
- 命令模式:默认模式,可以实现移动光标,剪切/粘贴文本
- 插入(Insert)或编辑模式:用于修改文本
- 扩展命令(extended command )或命令行模式:保存,退出等
打开vim默认进入命令模式,所有按键操作在屏幕上不可见!!!
-
命令模式>>插入模式
i 在当前光标'所在处输入 #当前光标处插入 a 在当前光标'所在处后面输入 #紧跟当前光标之后 I 在当前光标所在行的'行首输入 #本行首 A 在当前光标所在行的'行尾输入 #本行尾 o 在当前光标'所在行的下一行新建行 #下一行新建行首 O 在当前光标'所在行新建行 #挤进当前行
-
从插入模式返回
按 esc
-
命令模式>> 扩展命令模式
按 :
-
从扩展命令模式返回
按 esc 或 enter #一般按enter即为在扩展命令模式执行了一条命令
1.4 命令模式
命令模式功能强大,只是按键时看不到输入内容,所以需要大量的记忆才能更好的使用
1.4.1 退出VIM
ZZ 保存并退出
ZQ 不保存退出
1.4.2 光标跳转
字符间跳转:
h: 左 l: 右 j: 下 k: 上
#指定移动步数:#cmd
如 5k 表示直接上移5行
#直接数字加方向键也能实现同样功能!!!!!!
单词间跳转:
w: 下一个单词的词首
e:当前或下一个单词的词尾
b:当前或#前一个单词的词首(back往回走)
#cmd:由#指定一次跳转的单词数
句间移动:
) 下一句 ( 上一句
#判断依据为句号. 而且必须有至少一个空格,如a.b不能算是句号
段落间移动:
} 下一段 { 上一段
#判断依据为空行
行间移动:
1G或gg 第一行
G 最后一行
#跳转至第N行:
NG 或者 EX模式下输入N
行首行尾跳转:
^ 跳转至行首的第一个非空白字符
0 跳转至行首
$ 跳转至行尾
当前页跳转:
H:页首(head) M:页中(middle) L:页底(last)
#下述移动是指上下滑动调整查看效果,而不是编辑内容!!!!!!!!!
zt:将光标所在当前行移到屏幕顶端
zz:将光标所在当前行移到屏幕中间
zb:将光标所在当前行移到屏幕底端
命令模式翻屏操作:
直接pgup、pgdown即可
1.4.3 字符编辑
在命令模式下也能进行部分编辑操作
x 删除光标处的字符
#x 删除从光标处起始的全部#个字符 #累计删除!!
xp 交换光标所在处的字符及其后面字符的位置 #位置替换
~ 转换大小写
J 删除 当前行尾的 换行符 #随便光标处在哪儿
1.4.4 替换命令(replace)
r 替换光标所在处的字符(定点改错) #先输入r,再输入想要替换的内容
R 切换成REPLACE模式,按ESC回到命令模式 #替换模式,输入内容将会覆盖原文件内容
1.4.5 删除命令(delete)
d 删除命令 #可结合光标跳转字符,实现范围删除
d$ 删除到行尾 = D
d^ 删除到非空行首
d0 删除到行首
dw 删除单词
de 删除单词
db 删除前面的单词
dd:删除光标所在的行 #实际上是剪切
Ndd:删除 #从本行开始往下N行
dG:从本行开始往后全部删除
dgg:从本行开始往前全部删除
1.4.6 复制命令(yank)
y 复制,行为相似于d剪切
同理也可以结合光标跳转字符,实现范围操作
yy或Y 复制本行
#yy 复制多行(从本行往下#行)
!!!应注意:单独按 d 或 y 是不起作用的
1.4.7 粘贴命令(paste)
小p 若缓存的是整行,则贴在光标下一行,否则跟在后方
大P 若缓存的是整行,则贴在光标上一行,否则跟在前方
1.4.8 改变命令(change)
与 d 的功能完全一致,但是完成操作后自动切换到插入模式
比如:
cc :即为删除本行并进入插入模式,cc=S
C:删除当前光标到行尾,并切换成插入模式,相当于c$
1.4.9 搜索///
#pattern可以是普通字符或正则表达式
/PATTERN:从当前光标所在处向文件尾部查找
?PATTERN:从当前光标所在处向文件首部查找
#出现多个结果之后,按回车 并用 n N 进行选择
n:与命令同方向
N:与命令反方向
1.4.10 撤销u与重复 .
u 撤销最近的更改
U 撤消 当光标落在这行之后 在此行进行的所有更改
#u 撤销之前的多次更改
Ctrl - r #撤销 上一次“撤消”操作
. #重复上一次操作!!!!!!!!!!!!!!!!!
N. 重复前一个操作N次
1.4.11 高级用法
<start position><command><end position>
#常见Command:y 复制、d 删除、gU 变大写、gu 变小写
比如 0y$ 命令
0 → 先到行头
y → 从这里开始拷贝
$ → 拷贝到本行最后一个字符
#因此0y$表示复制这一行 = yy
特别地:范围操作
di" 光标在" "之间,则删除" "之间的内容
yi( 光标在( )之间,则复制( )之间的内容
vi[ 光标在[ ]之间,则选中[ ]之间的内容
dtx 删除字符#直到遇见光标之后的第一个 x 字符 t=till
ytx 复制字符#直到遇见光标之后的第一个 x 字符
1.5 扩展命令模式(末行)
按“ : ”进入Ex模式 ,创建一个命令提示符: 处于底部的屏幕左侧
ex模式基本命令
w 写(存)磁盘文件
wq 写入并退出
x 写入并退出
X 加密
q 退出
q! 不存盘退出,即使更改都将丢失
r file (输入)读指定文件内容到当前文件中
w file (输出)将当前文件内容写入另一个文件
!command 执行命令 #意思是不退出vim的情况下执行命令
r!command 读入命令的输出
ex模式高级用法
1.5.1 地址定界
以行为基本单位
:start_pos,end_pos cmd
# 具体第#行,例如2表示第2行
. 当前行
$ 最后一行
N,M 表示第N行到第M行
% 全文, 相当于1,$
N,+M 表示第N行到第N+M行
.,$-1 当前行到倒数第二行
/pattern/ 从当前行向下查找,直到匹配pattern的第一行,即:正则表达式
/pat1/,/pat2/ 从第一次被pat1模式匹配到的行开始,一直到第一次被pat2匹配到的行结束
N,/pat/ 从指定行开始,一直找到第一个匹配patttern的行结束
/pat/,$ 向下找到第一个匹配patttern的行到整个文件的结尾的所有行
地址定界后跟一个编辑命令,即可进行批量范围操作
d 删除
y 复制
w file 将范围内的行另存至指定文件中
r file 在指定位置插入指定文件中的所有内容
#比如2,5 d 表示删除2~5行
1.5.2 查找并替换 s///
s/要查找的内容/替换为的内容/[修饰符]
#直接s默认处理光标所在行,全文修改需要加%,即为%s///
#要查找的内容:可使用正则表达式模式
#替换为的内容:不能使用PATTERN,但可以使用\1, \2, ...等后向引用符号
还可以使用“&”引用前面查找时查找到的整个内容
#修饰符:
i 忽略大小写
g 全局替换 #默认情况下,每一行只替换第一次出现的目标
gc 全局替换,每次替换前询问
特别地,s///也可以换为s@@@...等其他字符
s@/etc@/var@g #将光标所在行的全部/etc替换为/var
s#/boot#/#i #将/boot替换为/ 且不区分大小写
1.5.3 个性化设置
- 显示行号——显示:set number,简写 set nu
- 设置光标所在行的标识线——启用:set cursorline,简写 set cul
- 忽略大小写——启用:set ignorecase,简写 set ic
- 自动缩进——启用:set autoindent,简写 set ai
- 复制保留格式——启用:set paste
- 显示Tab和换行符 ^I 和$显示——启用:set list
- set et 表示用空格代替Tab
- set ts=4 表示指定用4个空格替代Tab
- 高亮搜索——启用:set hlsearch
- 语法高亮——启用:syntax on
- 设置文本宽度——set textwidth=65 (vim only)
- .........
以上所有设置的关闭方式相同:set noCMD
永久保存设置,保存在配置目录
1.6 可视化模式
用方向键和其他字符跳跃快捷键模拟鼠标选中操作
被选中的文字可被删除,复制,变更,过滤,搜索,替换等
进入此模式的快捷键:
- v 面向字符
- V 面向整行
- ctrl-v 面向矩形块
范例:在文件行首插入#字符
输入gg光标回到第一行
输入ctrl+v 进入可视化模式
输入 G 跳到最后1行,此时即选中了所有行
输入 I 切换至插入模式(I进入插入模式且在行首输入)
输入 #
按 ESC 键,插入完成
1.7 多文件模式
vim FILE1 FILE2 FILE3 ...
:next 下一个
:prev 前一个
:first 第一个
:last 最后一个
:wall 保存所有
:qall 不保存退出所有
:wqall 保存退出所有
1.8 多窗口模式
1.8.1 多文件分割
vim -o|-O FILE1 FILE2 ...
-o: 上下分割
-O: 左右分割(vim only)
在窗口间切换:Ctrl+w, Arrow
1.8.2 单文件窗口分割
单个文件切割后相当于两个窗口同时显示同一个文件
Ctrl+w,s:split, 水平分割
Ctrl+w,v:vertical, 垂直分割
ctrl+w,q:取消相邻窗口
ctrl+w,o:取消全部窗口
:wqall :退出
1.9 vim的寄存器
寄存器即为多个剪贴板
- 字母寄存器
有26个字母命名寄存器和1个无命名寄存器,常存放不同的剪贴版内容,可以不同会话间共享
寄存器为 "a
使用时输入:数字 "a yy
3"tyy 表示复制3行到t寄存器中
"tp 表示将t寄存器内容粘贴,位置为当前光标所在行下面
未指定,将使用无命名寄存器,即为普通的复制粘贴操作
- 数字寄存器
还有10个数字寄存器,用0,1,…,9表示,0存放最近复制内容,1存放最近删除内容
当新的文本变更和删除时,1转存到2,2转存到3,以此类推
数字寄存器不能在不同会话间共享
1.10 标记和宏(macro)
作用是标记书签
输入ma :将当前位置标记为a
输入 'a 跳转到a标记的位置
26个字母均可做标记, mb 、 mc 等等
qa 录制宏 a,a为宏的名称
q 停止录制宏
@a 执行宏 a
@@ 重新执行上次执行的宏
录制宏 是录制位置还是录制一系列操作???
1.11 编辑二进制文件
涉及 xxd 命令
#以二进制方式打开文件
vim -b binaryfile
#扩展命令模式下,利用xxd命令转换为可读的十六进制
:%!xxd
#插入模式下,编辑二进制文件
#扩展命令模式下,利用xxd命令转换回二进制
:%!xxd -r
#保存退出
1.12 易错点&重点
- vim不支持ERE!!!!!
vim内使用set list显示不可见字符
练习题:
1、在vim中设置tab缩进为4个字符
配置文件路径为/etc/vimrc
set et
set ts=4
2、复制/etc/rc.d/init.d/functions文件至/tmp目录,替换/tmp/functions文件中的/etc/sysconfig/init为/var/log
[10:22:33root@CentOS8/~]# cp -a /etc/rc.d/init.d/functions /tmp
[10:22:58root@CentOS8/~]# ls /tmp/
functions vmware-root_744-2957583465 vmware-root_795-4257200573
ks-script-m0p456v5 vmware-root_760-2990613113
[10:23:12root@CentOS8/~]# vim /tmp/functions
#vim进入文件之后,执行下述命令
:%s@/etc/sysconfig/init@/var/log@g
#正确结果在63,64两行
3、删除/tmp/functions文件中所有以#开头,且#后面至少有一个空白字符的行的行首的#号
#首先明确符合条件的有30行
[10:38:55root@CentOS8/~]# grep -c "^#[[:blank:]]\+" /tmp/functions
30
#vim进入文件之后,执行下述命令
:%s/^#[[:blank:]]\+// 第二处参数不输入表示替换为空,即删除 末尾不加g表示只处理行首
#确认已处理完毕
[10:53:52root@CentOS8/~]# grep -c "^#[[:blank:]]\+" /tmp/functions
0
2 文本处理常用命令
2.1 文件内容查看命令
2.1.1 常规查看cat
cat 可以查看文本内容
cat [OPTION]... [FILE]...
-n:对显示出的每一行进行编号
-b:对非空行编号 命令 nl 显示行号,相当于cat -b
-s:压缩连续的空行成一行
-E:显示行结束符$
-T:显示TAB为^I
-A:显示所有控制符
#其他相关命令:
tac '按照行号逆向显示文本内容
rev '将同一行的内容逆向显示
特别地,若无指定文件或文件名为 - ,表示从标准输入接收信息
[20:28:01root@CentOS8data]#cat
tttt
tttt
reeghwwh
reeghwwh
^C
[20:32:02root@CentOS8data]#cat -
thsrb
thsrb
esrhaeth
esrhaeth
^C #使用Ctrl+C 退出
Windows中的文本文件与Linux中格式有所不同
- Windows换行——回车+换行
- Linux换行——换行(\n)
对于一些类似换行、Tab...等不可见字符,可使用 -A 选项进行显示
[20:37:09root@CentOS8data]#cat nn.txt
qwe
asdf
zxc
[20:37:19root@CentOS8data]#cat -A nn.txt
qwe$
asdf $ #此处有空格
zxc^I^I$ #此处有Tab
两种逆向显示:
[20:43:54root@CentOS8data]#cat cat.log
123
456
789
[20:44:02root@CentOS8data]#tac cat.log
789
456
123
[20:44:07root@CentOS8data]#rev cat.log
321
654
987
2.1.2 分页查看more与less
文本篇幅较大时,用cat查看不太方便,此时应使用more命令
-
进入more终端之后的快捷键
换行 -- 回车键 上翻页 -- b 下翻页 -- 空格键
使用more命令查看,移动到最后一行时自动退出
为了反复查看文件,可使用less命令(less终端内不显示进度百分比)
-
进入less终端之后的快捷键
#换行翻页与more相同 跳到首行 -- g 跳到末行 -- G 搜索关键词 -- /keyword 退出终端 -- q
与管道配合使用
若已知输出结果会是大篇幅内容,可提前用管道连接more或less
例如:ls -R /etc/ | less
2.1.3 按行抽取head与tail
head | tail | |
---|---|---|
默认值 -n 10 | 输出前10行 | 输出后10行 |
-n +5 | 输出前5行 | 从第5行往后全部输出 |
-n -5 | 砍掉最后5行 | 输出后5行 |
大篇幅文件,若只需要查看前几行,可使用head命令
不指定行数,head默认输出前10行
head [-n N] file N为指定的行数
head [-c N] file N为指定的字节数
[10:00:26root@CentOS8~]#head -n 5 /etc/init.d/functions
# -*-Shell-script-*-
#
# functions This file contains functions to be used by most or all
# shell scripts in the /etc/init.d directory.
#
[10:28:55root@CentOS8~]#echo 12345 | head -c 3
123
特别地,行数为负数时,如head -n -5 表示 去除最后5行
与之相反,tail命令则表示显示文件指定的最后几行
不指定默认输出最后10行,同样也支持 -c 字节数
[10:11:41root@CentOS8~]#tail -n 5 /etc/shadow
sshd:!!:18445::::::
avahi:!!:18445::::::
tcpdump:!!:18445::::::
jacklee:$6$QlCPFppDpXzzYYRB$Zot.igaBz4y8VWcAOKVjEfo54fnvC9GKd2DwmxOTXFCES5UU0zolUzUduI/607qQW6iLV04QFjxheuva/3lyd0:0:3:42:14:7:18545:
ass:!!:18468:0:99999:7:::
[10:29:45root@CentOS8~]#echo 12345 | tail -c 3
45
#此处 -c 3 表示输出最后3个字符
#因为echo命令输出普通字符默认最后有一个换行符,\n,占一个字节
#因此最后3个字节为 4 5 \n
特别地,tail命令行数前使用 + 号,如 -n +3 表示从第3行往后全部输出
[10:23:50root@CentOS8~]#seq 9 | tail -n 3
7
8
9
[10:24:08root@CentOS8~]#seq 9 | tail -n +3
3
4
5
6
7
8
9
@@tail实用功能( -f 选项):持续监测文件是否有追加内容
终端1:ping www.baidu.com > /data/ping.log
终端2:tail -f /data/ping.log
#与tail -f功能类似的命令tailf
#唯一区别是 当文件不可访问时,tailf命令会自动退出
2.1.4 按列抽取cut
cut 命令以指定分隔符对文本文件或STDIN数据的每行内容进行切割
默认分隔符为TAB
cut [OPTION]... [FILE]...
三种类似功能:指定 字节b/字符c/字段f 序号或范围
-b 指定字节 -n 不分割多字节字符,如汉字 经常与 -b 组合使用
-c 指定字符
-f 按指定分隔符进行分割 -d指定分隔符 与 -f组合使用
N 定位到第N个
N- 从第N个字节、字符、字段到结尾;
N-M 从第N个字节、字符、字段到第M个(包括M在内)字节、字符、字段;
-M 从第1个字节、字符、字段到第M个(包括M在内)字节、字符、字段。
#混合使用:2-4,7 = 2,3,4,7
不常用功能:-b 、 -c
[16:15:06root@CentOS8data]#cat f3
123456789
ABCDEFGHI
[16:15:10root@CentOS8data]#cut -b 5 f3
5
E
[16:17:23root@CentOS8data]#cut -b 5- f3
56789
EFGHI
[16:17:44root@CentOS8data]#cut -b 5-6 f3
56
EF
[16:17:49root@CentOS8data]#cut -b -5 f3
12345
ABCDE
-c 与 -b 结果相同#是因为单个alnum恰好是一个字节
[16:17:54root@CentOS8data]#cut -c 2 f3
2
B
[16:18:22root@CentOS8data]#cut -c 2- f3
23456789
BCDEFGHI
[16:18:29root@CentOS8data]#cut -c 2-4 f3
234
BCD
[16:18:34root@CentOS8data]#cut -c -2 f3
12
AB
-nb的作用:防止切割多字节字符(可认为等效于-c)
#已知每个汉字大小为3byte!!!
-
正常给定正确的byte
[16:41:44root@CentOS8data]#cat f1 我来烤烤你 [16:41:49root@CentOS8data]#cut -b 1 f1 #一个字节,不足以显示出第一个汉字 [16:43:21root@CentOS8data]#cut -b -3 f1 #每3个字节即可完整显示一个汉字 我 [16:43:23root@CentOS8data]#cut -b -6 f1 我来 [16:43:26root@CentOS8data]#cut -b -9 f1 我来烤 [16:43:28root@CentOS8data]#cut -b -12 f1 我来烤烤 [16:43:34root@CentOS8data]#cut -b -15 f1 我来烤烤你 [16:43:40root@CentOS8data]#cut -c -1 f1 #每个汉字一个字符,即可按个数显示 我 [16:43:58root@CentOS8data]#cut -c -2 f1 我来 [16:44:00root@CentOS8data]#cut -c -3 f1 我来烤 [16:44:02root@CentOS8data]#cut -c -4 f1 我来烤烤 [16:44:04root@CentOS8data]#cut -c -5 f1 我来烤烤你
-
不是3的整数倍,使用 -n 可以不分割汉字(多字节字符)
[16:51:38root@CentOS8data]#cut -nb -1 f1 我 [16:51:54root@CentOS8data]#cut -nb -3 f1 我来烤 [16:51:57root@CentOS8data]#cut -nb -5 f1 我来烤烤你
常用功能:-f(需要先用-d指定分隔符,不指定则为tab)
-
不指定的情况
[11:58:36root@CentOS8data]#cat f1 1 2 3 4 5 6 7 8 9 [11:58:40root@CentOS8data]#cat -A f1 #确认分隔符为TAB 1^I2^I3$ 4^I5^I6$ 7^I8^I9$ [11:58:44root@CentOS8data]#cut -f 2 f1 2 5 8 [11:59:19root@CentOS8data]#cut -f 3 f1 3 6 9 [11:59:22root@CentOS8data]#cut -f 2-3 f1 #2-3表示范围 2 3 5 6 8 9 [11:59:27root@CentOS8data]#cut -f 1,3 f1 1 3 4 6 7 9
-
指定分隔符(取范围时,输出结果会包含分隔符!!!)
[16:23:43root@CentOS8data]#cat f1 1#2#3#4#5#6#7#8#9 A#B#C#D#E#F#G#H#I [16:30:52root@CentOS8data]#cut -d "#" -f 5 f1 5 E [16:24:46root@CentOS8data]#cut -d "#" -f -5 f1 (取范围,是1#2#3#4#5而不是12345) 1#2#3#4#5 A#B#C#D#E [16:31:00root@CentOS8data]#cut -d "#" -f 5- f1 5#6#7#8#9 E#F#G#H#I [16:31:09root@CentOS8data]#cut -d "#" -f 2-4 f1 2#3#4 B#C#D
其他功能:在输出结果中指定需要显示的分隔符
--output-delimiter=STRING指定输出分隔符
#以':'为分隔符取出文件f2的第2~3列,并使输出结果中的分隔符显示为=
[12:07:34root@CentOS8data]#cat f2
1:2:3
4:5:6
[12:07:39root@CentOS8data]#cut -d ":" -f 2,3 f2
2:3
5:6
[12:08:46root@CentOS8data]#cut -d ":" --output-delimiter="=" -f 2,3 f2
2=3
5=6
其他功能:取反 complement
#以:为分隔符,取出/etc/passwd文件中的第1,3,4,5列
[16:31:16root@CentOS8data]#cut -d : -f 1,3-5 /etc/passwd
root:0:0:root
bin:1:1:bin
daemon:2:2:daemon
adm:3:4:adm
......
#以:为分隔符,取出/etc/passwd文件中除了第1,3,4,5列之外的其他列
[16:39:40root@CentOS8data]#cut -d : -f 1,3-5 --complement /etc/passwd
x:/root:/bin/bash
x:/bin:/sbin/nologin
x:/sbin:/sbin/nologin
x:/var/adm:/sbin/nologin
2.1.5 合并文件paste
默认以行为单位,合并多个文件同行号的列到一行
合并文件的拼接处默认以TAB分隔
paste [OPTION]... [FILE]...
-d 指定分隔符,默认用TAB
-s 先把各文件所有行合成一行,再上下进行拼接 #N个文件合并结果为N行
[17:04:20root@CentOS8data]#cat f2
12441
574575
789789
[17:04:22root@CentOS8data]#cat f3
ABCD
QWER
ZXCV
[17:04:24root@CentOS8data]#paste f2 f3 #正常合并,同行拼接
12441 ABCD
574575 QWER
789789 ZXCV
[17:04:34root@CentOS8data]#paste -d @ f2 f3 #合并同时指定分隔符
12441@ABCD
574575@QWER
789789@ZXCV
[17:04:47root@CentOS8data]#paste -s f2 f3 #先换成一行再叠加合并
12441 574575 789789
ABCD QWER ZXCV
[17:05:24root@CentOS8data]#paste -s -d ':' f2 f3 #叠加与指定分隔符同时作用
12441:574575:789789
ABCD:QWER:ZXCV
2.2 文本分析工具(重点)
2.2.1 统计数据wc
对指定文本文件或STDIN的各项指标进行统计
包括:文件的行总数、单词总数、字节总数和字符总数
wc [opt] [file]
常用选项
-l 只计数行数
-w 只计数单词总数
-c 只计数字节总数
-m 只计数字符总数
-L 显示文件中#最长行的长度 即为文件宽度
不加选项时默认统计前三项
[11:30:17root@CentOS8data]#wc cat.log
28 173 946 cat.log
# 28行 173词 946字节
应用举例:
-
统计登录用户的数量
[11:34:09root@CentOS8data]#who | wc -l 2
-
统计conf后缀文件的个数
[11:36:11root@CentOS8data]#ls /etc/*.conf | wc -l 41
2.2.2 排序整理sort
对文件的所有行进行排序
默认:数字在字母之前、字母排序不分大小写
#也可将每行切分成字段再进行排序
-t 指定切割字符
-k 指定以切割后第几段排序
-n 指定以数值大小排序
-r 倒序排列
-R 随机排列
-b 忽略每行行首的若干个空格字符
[20:34:55root@CentOS8/data]# cat jackB
abd
ABd
4Am
5be
Bcc
b56
Car
cvb
c4d
[20:35:00root@CentOS8/data]# sort jackB #先数字再字母,字母相同再看第二列
4Am
5be
abd
ABd
b56
Bcc
c4d
Car
cvb
#将/etc/passwd文件以:分隔后的第三字段按数字排序,取前5行
[20:49:22root@CentOS8/data]# sort -t ":" -k3 -n /etc/passwd| head -n 5
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
2.2.3 去重处理uniq
以行为单位去除重复内容(只去除连续重复行)
-c 显示重复次数
-d 只显示连续重复行(重复但不连续的不算!!!)
-u 只显示不连续重复的行
[20:59:29root@CentOS8/data]# cat -n jackC
1 111
2 111
3 111
4 2345
5 666
6 666
7 2345
8 888
[20:59:43root@CentOS8/data]# uniq jackC #去除连续重复的行
111
2345
666
2345
888
[21:00:03root@CentOS8/data]# uniq -c jackC
3 111 #连续重复3次
1 2345
2 666 #连续重复2次
1 2345
1 888
[21:01:04root@CentOS8/data]# uniq -d jackC #出现过连续重复的行 的内容
111
666
[21:01:22root@CentOS8/data]# uniq -u jackC #没出现过连续重复的行
2345
2345
888
2.2.4 异同比较diff
对比分析两个普通文件的不同之处(命令cmp比较两个二进制文件的区别)
[21:09:37root@CentOS8/data]# echo 2020-{01..12} | tr ' ' '\n' > jackA
[21:10:16root@CentOS8/data]# cat jackA
2020-01
2020-02
2020-03
2020-04
2020-05
2020-06
2020-07
2020-08
2020-09
2020-10
2020-11
2020-12
[21:10:20root@CentOS8/data]# echo 2020-{01..8} | tr ' ' '\n' > jackB
[21:10:46root@CentOS8/data]# cat jackB
2020-01
2020-02
2020-03
2020-04
2020-05
2020-06
2020-07
2020-08
[21:10:52root@CentOS8/data]# diff jackA jackB
9,12d8 #表示9~12行有不同
< 2020-09
< 2020-10
< 2020-11
< 2020-12
选项 -y可以并排对比 -W指定并排的间距
(#已手动修改了jackB两处内容)
[21:17:35root@CentOS8/data]# diff -y -W 30 jackA jackB
2020-01 2020-01
2020-02 2020-02
2020-03 | 2018-03 |表示不同之处
2020-04 2020-04
2020-05 2020-05
2020-06 | 2018-06
2020-07 2020-07
2020-08 2020-08
2020-09 < < 表示后面文件少一行(同理 > 表示前面少)
2020-10 <
2020-11 <
2020-12 <
选项 -u 用来输出统一的(unified)diif格式文件(适合用于补丁文件)
[root@centos8/~]# diff -u jackA jackB
--- jackA 2020-08-05 19:17:03.738281873 +0800
+++ jackB 2020-08-05 19:17:57.517282028 +0800
@@ -1,12 +1,8 @@ #表示两个文件的行数
2020-01
2020-02
-2020-03 #不同之处
+2018-03 #不同之处
2020-04
2020-05
-2020-06 #不同之处
+2018-06 #不同之处
2020-07
2020-08
-2020-09 #不同之处
-2020-10
-2020-11
-2020-12
patch命令:利用diff比较结果输出的内容进行还原
[root@centos8/~]# diff -u jackA jackB > jack.patch #保存补丁文件
[root@centos8/~]# rm -f jackB
[root@centos8/~]# patch -b jackA jack.patch
patching file jackA
#表示用补丁恢复文件jackB,并覆盖在jackA之中 同时 -b将jackA内容备份到jackA.orig
[root@centos8/~]# cat jackA (此即为jackB被恢复的内容)
2020-01
2020-02
2018-03
2020-04
2020-05
2018-06
2020-07
2020-08
[root@centos8/~]# cat jackB
cat: jackB: No such file or directory
[root@centos8/~]# cat jackA.orig (此即为jackA备份的内容)
2020-01
2020-02
2020-03
2020-04
2020-05
2020-06
2020-07
2020-08
2020-09
2020-10
2020-11
2020-12
[root@centos8/~]#
cmp命令:比较二进制程序的源码不同之处
[root@centos8/~]# ll /usr/bin/dir /usr/bin/ls
-rwxr-xr-x. 1 root root 166448 May 12 2019 /usr/bin/dir
-rwxr-xr-x. 1 root root 166448 May 12 2019 /usr/bin/ls
[root@centos8/~]# ll /usr/bin/dir /usr/bin/ls -i
201508553 -rwxr-xr-x. 1 root root 166448 May 12 2019 /usr/bin/dir
201508574 -rwxr-xr-x. 1 root root 166448 May 12 2019 /usr/bin/ls
[root@centos8/~]# diff /usr/bin/dir /usr/bin/ls
Binary files /usr/bin/dir and /usr/bin/ls differ
[root@centos8/~]# cmp /usr/bin/dir /usr/bin/ls
/usr/bin/dir /usr/bin/ls differ: byte 737, line 2
[root@centos8/~]# hexdump -s 730 -Cn 7 /bin/dir
000002da 00 00 47 4e 55 00 b0 |..GNU..|
000002e1
[root@centos8/~]# hexdump -s 730 -Cn 7 /bin/ls
000002da 00 00 47 4e 55 00 93 |..GNU..|
000002e1
[root@centos8/~]#
3 grep与正则表达式
3.0 grep命令
grep [op]... parttern [file]...
选项:
--color=auto #表示对匹配到的结果着色处理(默认开启)
[11:50:29root@CentOS8/~]# alias grep
alias grep='grep --color=auto'
[11:50:34root@CentOS8/~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
排除过滤 - v:
grep默认只显示符合条件的行,- v 选项只显示不符合条件的内容
[11:52:17root@CentOS8/~]# grep -v root /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
.......
**忽略大小写- i **:gerp默认大小写敏感,- i 选项忽略大小写
[14:02:53root@CentOS8/~]# grep ROOT /etc/passwd #不加选项无输出结果
[14:07:15root@CentOS8/~]# grep -i ROOT /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
显示行号 -n :文本过多时,显示行号方便查看
(显示匹配结果在原文中的行号)
[14:07:23root@CentOS8/~]# grep -n root /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
**显示行数量 - c **, 只显示有多少行符合条件
[14:48:55root@CentOS8/~]# grep -c root /etc/passwd
2
- o 只显示keywords:- o 只显示所有匹配的内容,可知keywords数量
[15:05:16root@CentOS8/~]# grep -o root /etc/passwd
root
root
root
root
静默模式:- q 选项执行命令但不输出结果,常用于脚本条件判断
#执行后查看 $? 变量可知是否匹配。 $?=0表示有匹配结果
[15:07:09root@CentOS8/~]# grep aaaaa -q /etc/passwd
[15:11:52root@CentOS8/~]# echo $?
1 #表示无法匹配到'aaaaa'
[15:12:00root@CentOS8/~]# grep root -q /etc/passwd
[15:12:07root@CentOS8/~]# echo $?
0
ABC匹配结果附带前后行一起输出
-A 表示附带后面N行
-B 表示附带前面N行
-C = '-A' + '-B'
#选项加上-n是为了证实确实是匹配结果的后面3行
[15:12:09root@CentOS8/~]# grep root -nA3 /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
2-bin:x:1:1:bin:/bin:/sbin/nologin
3-daemon:x:2:2:daemon:/sbin:/sbin/nologin
4-adm:x:3:4:adm:/var/adm:/sbin/nologin
--
10:operator:x:11:0:operator:/root:/sbin/nologin
11-games:x:12:100:games:/usr/games:/sbin/nologin
12-ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
13-nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
选项 - e 多个条件满足其一(几个条件就有几次 - e )
特别地, - E 表示使用扩展正则表达式
-
逻辑 或
[15:17:15root@CentOS8/~]# grep -e root -e jack /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin jacklee:x:1000:1000:jacklee:/home/jacklee:/bin/bash [15:19:46root@CentOS8/~]# grep -e root -e aaaa /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin
-
过滤规则过多,将其写在文件中使用选项 - f 进行匹配(逻辑 = 或)
因为太多 - e 写起来太麻烦
[15:34:59root@CentOS8/data]# cat a.txt root body system [15:35:01root@CentOS8/data]# grep -f a.txt /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin systemd-resolve:x:193:193:systemd Resolver:/:/sbin/nologin
- **选项 - f 另一个功能:用于取两文件的相同行****
[root@centos8/~]# grep -f jackA jackA.orig 2020-01 2020-02 2020-04 2020-05 2020-07 2020-08
-
过滤规则过多,将其写在文件中使用选项 - f 进行匹配(逻辑 = 或)
-
逻辑 与(使用管道而不是 - e )
[15:26:01root@CentOS8/~]# grep root /etc/passwd | grep bash root:x:0:0:root:/root:/bin/bash [15:26:15root@CentOS8/~]# grep root /etc/passwd | grep aaaaa #无结果 [15:26:25root@CentOS8/~]#
选项 - w 匹配单个单词
单词判断依据——字母数字下划线连续组合都视为单词
单词判断依据——字母数字下划线连续组合都视为单词
单词判断依据——字母数字下划线连续组合都视为单词
[15:26:25root@CentOS8/~]# grep jack /etc/passwd
jacklee:x:1000:1000:jacklee:/home/jacklee:/bin/bash #包含jack有结果
[15:29:21root@CentOS8/~]# grep -w jack /etc/passwd #指定jack无结果
[15:29:38root@CentOS8/~]# grep -w jacklee /etc/passwd
jacklee:x:1000:1000:jacklee:/home/jacklee:/bin/bash
3.1 基本正则表达式
- 通配符用于匹配文件名
- 正则表达式用于匹配复杂的文本内容,可理解为增强版的通配符功能
正则表达式把字符和次数分开表达
正则表达式把字符和次数分开表达
正则表达式把字符和次数分开表达
正则表达式把字符和次数分开表达
基本格式为引号括起来:
"PATTERN" 或 'PATTERN'
正则表达式的元字符按功能分四类,下面分别介绍
3.1.1字符串匹配
通配符 . 表示 . 字符本身,无特别意义
正则表达式 . 表示#任意单个字符(可以是汉字),为表示.需要转义为 \.
'使用( )分组也视为一个字符!!!!
[0-9] 或 [[:digit:]] 匹配单个数字
#以下3项是正则表达式特有!!!!!!!!!
[a-z] 或 [[:lower:]] 匹配单个小写字母
[A-Z] 或 [[:upper:]] 匹配单个大写字母
[a-zA-Z]或[[:alpha:]] 任意单个字母 #注意取反的格式:[^[:alpha:]]
[[:punct:]] 单个标点符号
[[:print:]] 单个可打印的所有字符
[[:graph:]] 单个可打印的非空白字符
[[:blank:]] #空格和Tab
[[:space:]] #任意单个空白字符(包括但不限于空格和Tab)
注意:
- [a-d]在通配符和正则表达式中的区别!!!
- [:lower:]是一个元字符,表示任意一个小写字母
#在命令中,[[:lower:]]表示匹配任意一个小写字母,其他类似
- .表示任意单个字符,#可用 \.转义 表示.字符本身
- 可以混合使用,如[a-zA-Z]、[jack1-6]
-
正则匹配单个字符
[15:35:03root@CentOS8/data]# grep "r..t" /etc/passwd root:x:0:0:root:/root:/bin/bash #本行的"root"符合"r..t" operator:x:11:0:operator:/root:/sbin/nologin ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin #本行的"r/ft"符合"r..t"
-
正则中括号功能
-
匹配指定字符集 特别注意 [a-d] = a b c d !!!
#查看文件中的数字 [15:52:03root@CentOS8/data]# grep "[0-9]" /etc/redhat-release CentOS Linux release 8.0.1905 (Core) #此处数字已经彩色显示 #查看 ip a 输出的大写字母 [16:04:45root@CentOS8/data]# ip a | grep "[[:upper:]]" 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue stateUNKNOWN group default qlen 1000 2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 #所有大写字母已经彩色显示
-
中括号也可以任意指定某几个字符表示逻辑或
[16:12:12root@CentOS8/data]# ls jackA jackB jackC jackD [16:12:13root@CentOS8/data]# ls | grep "jack[AC]" jackA jackC [16:13:04root@CentOS8/data]# ls | grep "jack[^AC]" #取反 jackB jackD
-
3.1.2 匹配次数
指定某个内容出现的具体次数(keyword写在前)
只匹配前一个紧挨着的字符!!!!!!!!!!!!!!!!!!
* 表示匹配前面的字符# 0次或任意次 jack*表示字符k任意次,而不是jack!!!!
\? 表示匹配前面的字符# 0次或1次
\+ 表示匹配前面的字符# 至少1次
\{n\} 表示匹配前面的字符# 连续n次 与\{n,\}效果相同!!!!!!!!!!!
\{m,} 表示匹配前面的字符# 至少m次
\{,n\}表示匹配前面的字符# 最多n次
\{m,n\} 表示匹配前面的字符# m~n次
-
0次、单次与任意次
#下面"jacklee1*"表示匹配数字1而不是jacklee1 !!!!!!!! [16:39:05root@CentOS8/data]# grep "jacklee1*" jackA #包括0次 jacklee111 jacklee2222 jacklee33333 [16:40:48root@CentOS8/data]# grep "jacklee1\?" jackA #包括0次 jacklee111 jacklee2222 jacklee33333 [16:41:33root@CentOS8/data]# grep "jacklee1\+" jackA #至少1次 jacklee111
-
匹配指定次数(特别注意,最多N次:包括0次)
[16:46:53root@CentOS8/data]# grep "1\{1\}" jackA 表示1出现1次即可 jacklee111 [16:48:09root@CentOS8/data]# grep "1\{3\}" jackA 表示连续3个1即可 jacklee111 [16:48:47root@CentOS8/data]# grep "1\{5\}" jackA 表示连续5个1即可 [16:48:52root@CentOS8/data]# 原文件只有3个1,因此无匹配结果 [16:48:52root@CentOS8/data]# grep "3\{5\}" jackA jacklee33333 #原文件够5个3,因此有结果 [16:55:49root@CentOS8/data]# grep "2\{2,4\}" jackA 表示2~4个2都可 jacklee2222 [16:57:32root@CentOS8/data]# grep "2\{2,6\}" jackA 表示2~6个2都可 jacklee2222 [16:57:38root@CentOS8/data]# grep "2\{5,6\}" jackA [16:57:49root@CentOS8/data]# 原文件只有4个2,因此5~6次无匹配结果 [17:00:38root@CentOS8/data]# grep "3\{2,\}" jackA 表示3至少2连击 jacklee33333 [17:00:41root@CentOS8/data]# grep "3\{5,\}" jackA 表示3至少5连击 jacklee33333 [17:00:47root@CentOS8/data]# grep "3\{6,\}" jackA [17:00:50root@CentOS8/data]# 至少6连击,因此无匹配结果 [17:02:30root@CentOS8/data]# grep "1\{,2\}" jackA '表示最多只需要两个1即可 #表示最多2连击,因此2个1就已经足够匹配到 jacklee111 #同时,没有1也符合要求!!!因为0次也符合最多2次!!! jacklee2222 jacklee33333 [17:02:32root@CentOS8/data]# grep "1\{,4\}" jackA jacklee111 jacklee2222 jacklee33333
-
匹配正负数字(负数的负号 - 需要特殊处理!!)
[root@centos8/~]# echo -1 -2 223 -123 56 | egrep '-?[0-9]+' grep: invalid option -- '?' Usage: grep [OPTION]... PATTERN [FILE]... Try 'grep --help' for more information. #表示负数,需要转义负号!!! 3种办法均可 [root@centos8/~]# echo -1 -2 223 -123 56 | egrep '\-?[0-9]+' -1 -2 223 -123 56 [root@centos8/~]# echo -1 -2 223 -123 56 | egrep -- '-?[0-9]+' -1 -2 223 -123 56 [root@centos8/~]# echo -1 -2 223 -123 56 | egrep '(-)?[0-9]+' -1 -2 223 -123 56 [root@centos8/~]#
3.1.3 位置锚定
在指定位置搜索字符串
^ 表示行首
$ 表示行尾
\< 表示词首 = \bKEY
\> 表示词尾 = KEY\b
#单词的定义:数字字母下划线连续出现,无论多长都认为是一个单词
^$ 表示空行!!! #(无任何内容)
^[[:space:]]$ 表示空白行!!!#(只有不可见字符)
^PATTERN$ #匹配整行
\<PATTERN\> #匹配整个单词
-
整行范围匹配(行首 ^)
#查找以root开头的行 [17:25:09root@CentOS8/data]# grep "^root" /etc/passwd root:x:0:0:root:/root:/bin/bash #查找不以#开头的行!!!([^#]表示除了#) [17:41:42root@CentOS8/data]# cat /etc/fstab # # /etc/fstab # Created by anaconda on Tue Jul 28 20:19:00 2020 # # Accessible filesystems, by reference, are maintained under '/dev/disk/'. # See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info. # # After editing this file, run 'systemctl daemon-reload' to update systemd # units generated from this file. # UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0 UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2 UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0 UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0 [17:41:59root@CentOS8/data]# grep "^[^#]" /etc/fstab # UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0 UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2 UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0 UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0 [17:42:22root@CentOS8/data]# grep "^[^#].*" /etc/fstab # UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0 UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2 UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0 UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0 "^[^#]"与"^[^#].*"最终结果相同,可认为等效
-
整行范围匹配(行尾 $)
#查找以bash结尾的行 [18:01:17root@CentOS8/data]# grep "bash$" /etc/passwd root:x:0:0:root:/root:/bin/bash jacklee:x:1000:1000:jacklee:/home/jacklee:/bin/bash
-
全行匹配(^ $)
[18:04:11root@CentOS8/data]# cat jackB AAAA CCCCCCCC DDD EEEEEEE [18:04:23root@CentOS8/data]# grep -n "^D$" jackB #全行匹配精确=D才符合条件 [18:05:04root@CentOS8/data]# grep -n "^DDD$" jackB #精确=DDD,匹配成功 4:DDD [18:05:10root@CentOS8/data]# grep -n "^$" jackB #匹配空行,第2行匹配成功 2: [18:05:15root@CentOS8/data]#
-
基于单词进行锚定(\>或者\<)或者\b
[19:12:33root@CentOS8/data]# cat -n jackC 1 jack222 nnnn 2 jack555 nnnnn 3 jack888 mmmm 4 aaab888 kkkk 5 cccd888 rrrr [19:13:49root@CentOS8/data]# grep -n "\<jac" jackC 1:jack222 nnnn 2:jack555 nnnnn 3:jack888 mmmm [19:13:54root@CentOS8/data]# grep -n "\bjac" jackC \b写在前面表示词首 1:jack222 nnnn 2:jack555 nnnnn 3:jack888 mmmm [19:13:59root@CentOS8/data]# grep -n "8\>" jackC 3:jack888 mmmm 4:aaab888 kkkk 5:cccd888 rrrr [19:14:11root@CentOS8/data]# grep -n "8\b" jackC \b写在后面表示词尾 3:jack888 mmmm 4:aaab888 kkkk 5:cccd888 rrrr
3.1.4 分组和逻辑处理
分组:将多个字符 作为整体 来进行处理
正则表达式#分组的元字符:\(PATTERN\)
普通分组用法:
#查看包含(lee连续重复3次)的行
[19:25:27root@CentOS8/data]# cat jackA
jackjackjack
leeleelee
sjhdvbasjbvj
asjbfbaffnvjsn
[19:25:38root@CentOS8/data]# grep "\(lee\)\{3\}" jackA
leeleelee
后向引用:使用分组之后,后续再次引用只需要使用 \1、\2 等表示第一个、第二个分组
最适合用于vim搜索替换(形如 r..t 替换成 r..ter 的情况)
逻辑 或
除了使用选项 - e 还有符号 \| (其中\用来转义)
[19:30:00root@CentOS8/data]# cat jackC
cat
C
tomCat
Tom
#显示包含C或cat的行
[19:30:07root@CentOS8/data]# grep "C\|cat" jackC
cat
C
tomCat
#显示包含Cat或cat的行!!!!(组合用法)
[19:30:45root@CentOS8/data]# grep "\(c\|C\)at" jackC
cat
tomCat
[19:31:52root@CentOS8/data]# grep -e "cat" -e "Cat" jackC
cat
tomCat
@易错点&易混淆点
在ERE中,除了后向引用 \1 \2 写法,其余所有斜线都可省略,若再加斜线,表示匹配字符本身
-
中括号 [ ] 表示字符集,输入多个字符表示逻辑或
正则表达式中 . 表示任意单个字符,可以是汉字 [.] 表示 . 字符本身
-
用kuozhan正则表达式表示IP地址的优化思路
#利用次数锚定 [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} '显然过于重复,而且首尾无法严格表示3位数,如1111.0.0.8 10.0.0.111abc均可被匹配到 #利用次数锚定和位置锚定 \<[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\> '可严格锁定IP格式,但是过于重复 #再利用分组进行优化 \<([0-9]{1,3}\.){3}[0-9]{1,3}\> [root@centos8/~]# ip a|egrep -o "\<([0-9]{1,3}\.){3}[0-9]{1,3}\>" 127.0.0.1 10.0.0.8 10.0.0.255 #此时仍然无法过滤255以上的数字!!!
-
gerp命令的 -f 选项,两种完全不同的功能
grep -f a.txt /etc/passwd #表示将a.txt中的所有内容作为条件进行 逻辑或 匹配 grep -f jackA jackA.orig #输出两文件内容相同的行
-
位置锚定经典用法:
^[^#] 表示非#开头的行(同时也能排除空行) ^[^$#] = ^[^$]或^[^#] 表示除了空行和#开头行 (非$# = 非$或非#) 即 ^[^#] 与 ^[^$#] 效果相同
-
vim搜索替换中也可先使用位置锚定确定在哪一行进行操作
#在vim扩展命令模式输入如下内容: /位置锚定/s/pattren/替换内容/[修饰符]
a|b表示a或b,a|bcd表示a或bcd,(a|b)cd表示acd或bcd
[[:blank:]]与[[:space:]]的区别? blank表示空格和Tab space包括所有空格和制表符
-
逻辑或
- 选项 - e (几个条件写几次) - 选项 - f (多个条件写在文本中) - 字符 / | (用于两个分组差距很小的情况)
3.2 扩展正则表达式
为了在复杂规则中更加直观,省略了转义符 \
egrep 或者 grep -E 启用扩展RE
? 表示匹配前面的字符 # 0次或1次
+ 表示匹配前面的字符 # 至少1次
{n} 表示匹配前面的字符# 连续n次
{m,n} 表示匹配前面的字符# m~n次
( ) 表示分组
| 表示逻辑 或
#显示包含Cat或cat的行
[19:57:16root@CentOS8/data]# cat jackC
cat
C
tomCat
Tom
[19:57:53root@CentOS8/data]# egrep "(c|C)at" jackC
cat
tomCat
[19:57:57root@CentOS8/data]# grep -E "(c|C)at" jackC
cat
tomCat
3.3 三剑客之sed
3.3.0 易错点
-
地址与命令都不是必须的!
[root@centos8 ~]# sed '' 表示script内容为空,接收标准输入并echo输出 ddd ddd dddddddd dddddddd '不给地址:对全文进行处理 '不输入命令:表示只匹配行,不进行其他操作
-
模式空间内容 如何输出!!!!!!!!!(关键点)
-n 是选项,表示不管是否匹配到,都不输出内容(否则会逐行输出模式空间的内容) p 是命令,表示打印'被匹配到的每一行 d 是命令,表示删除在模式空间匹配到的行(用于排除) ' -n 与 p 搭配的意义:只显示匹配到的行,或 只显示编辑过的行 如果都不写 :输出全文,对应行已经被编辑 如果只有 -n:不输出任何内容 如果只有 p :输出全文,而且被编辑的行输出两次
使用script命令 d 取反时,在模式空间匹配到的行会被删除,未被匹配到的行会输出,达到了排除的效果
此时不再需要选项 -n,否则不会输出任何内容-
地址范围 多行的意义(表示范围而不是逻辑或!!!)
/pat1/,/pat2/ 从pat1匹配到的行 ~ pat2匹配到的行 #,/pat/ 从第#行 ~ pat匹配到的行
-
注意两者区别:
[root@centos8 ~]# sed -n '1,4p' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin [root@centos8 ~]# sed -n '1p;4p' /etc/passwd root:x:0:0:root:/root:/bin/bash adm:x:3:4:adm:/var/adm:/sbin/nologin
Script命令在一次操作中只能出现一种(比如 p 与 = 不能同时使用)
-
命令 a \, i \ ,c \ 上下插入行或替换本行
其中斜线可省略 a \txt 可写为 a txt 表示在下一行插入新行,内容为txt
地址和s///中的pattern默认都不支持ERE,需要启用选项 -r 或 -E
3.3.1 工作原理
sed 即 Stream EDitor,和 vi 不同,sed是行编辑器
Sed是从文件或管道中读取一行,处理一行,输出一行;再读取一行,再处理一行
每当处理一行时,把当前处理的行存储在临时缓冲区中,称为模式空间pattern space
一次处理一行的设计模式使得sed性能很高,sed在读取大文件时不会出现卡顿的现象
3.3.2 基本用法
sed [option]... 'script;script;...' inputfile...
其中"script" = /地址/动作
可以同时进行多个script操作,用 ; 隔开(如'2p;5p')
-n 不输出模式空间内容到屏幕,即不自动打印(核心选项)
-e 多点编辑(逻辑或)
-r/E 使用扩展正则表达式(扩展)
-i.bak 先备份文件并编辑源文件
-f /PATH/SCRIPT_FILE 从指定文件中读取编辑脚本
script地址
1.不给地址:对全文进行处理
2.单地址:
#:指定的行
$:最后一行
/pattern/:被此处模式所能够匹配到的每一行(正则)
3.范围地址:
#, #
#,+#
/pat1/,/pat2/ 从pat1匹配到的行 ~ pat2匹配到的行
#,/pat/ 从第#行 ~ pat匹配到的行
4. 步进:~
1~2 奇数行
2~2 偶数行
script命令(只能单独使用)
不输入命令:表示只匹配行,不进行其他操作
p 打印当前模式空间内容,追加到默认输出之后
d 删除模式空间匹配的行,并立即启用下一轮循环(取反)
a [\]text 在指定行下一行插入文本行,支持使用\n实现多行追加
i [\]text 在指定行上一行插入文本行
c [\]text 替换行为单行或多行文本
w /path/file 保存模式匹配的行至指定文件
r /path/file 读取指定文件的文本至模式空间中匹配到的行后
= 只显示匹配到的行号
! 模式空间中匹配行取反处理
s/pattern/string/修饰符
查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
替换修饰符:
g 行内全局替换
p 显示替换成功的行
w /PATH/FILE 将替换成功的行保存至文件中
1范例:可接受标准输入
[root@centos8 ~]# sed '' 表示script内容为空
ddd
ddd
dddddddd
dddddddd
fffffffffffffffffff
fffffffffffffffffff #使用ctrl+D退出
[root@centos8 ~]#
2范例:打印内容次数
#sed默认为echo一次,'p'再次打印,-n不打印
[root@centos8 ~]# sed '' /etc/issue
\S
Kernel \r on an \m
[root@centos8 ~]# sed -n '' /etc/issue
[root@centos8 ~]# sed 'p' /etc/issue
\S
\S
Kernel \r on an \m
Kernel \r on an \m
[root@centos8 ~]# sed -n 'p' /etc/issue #加一减一还是默认ehco
\S
Kernel \r on an \m
[root@centos8 ~]#
3范例:指定打印第几行
[root@centos8 ~]# sed -n '1p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@centos8 ~]# sed -n '2p' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
[root@centos8 ~]# sed -n '3p' /etc/passwd
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@centos8 ~]# ip a | sed -n '9p'
inet 10.0.0.8/24 brd 10.0.0.255 scope global noprefixroute ens160
4范例:使用/pattern/单地址匹配
[root@centos8 ~]# ip a | sed -n '/inet/p' #此处 p 是script命令!!
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
inet 10.0.0.8/24 brd 10.0.0.255 scope global noprefixroute ens160
inet6 fe80::e016:ece6:7e36:e2ec/64 scope link noprefixroute
[root@centos8 ~]# df|sed -n '/^\/dev\/sd/p' #此处 p 是script命令!!
/dev/sda2 104806400 3728680 101077720 4% /
/dev/sda5 52403200 398892 52004308 1% /data
/dev/sda1 999320 106688 823820 12% /boot
5范例:取地址范围
[root@centos8 ~]# seq 9 | sed -n '2,5p'
2
3
4
5
[root@centos8 ~]# seq 9 | sed -n '2,+2p'
2
3
4
[root@centos8 ~]# seq 9 | sed -n '7,$p'
7
8
9
6范例:步进取行
[root@centos8 ~]# seq 8 | sed -n '1~2p'
1
3
5
7
[root@centos8 ~]# seq 8 | sed -n '2~2p'
2
4
6
8
#使用命令 d 表示删除匹配结果,输出取反!!!(不能再加选项 -n)
[root@centos8 ~]# seq 6 | sed -n '1~2d'
[root@centos8 ~]# seq 8 | sed -n '1~2d' 因为d已经删除模式空间内容,再加-n就删除了原本的echo
[root@centos8 ~]# seq 8 | sed '1~2d'
2
4
6
8
[root@centos8 ~]# seq 8 | sed '2~2d'
1
3
5
7
7范例:多点编辑(两种方式)
[root@centos8 ~]# seq 8 | sed -e '3d' -e '5d' -e '7d'
1
2
4
6
8
[root@centos8 ~]# seq 8 | sed '1d;2d;5d'
3
4
6
7
8
8范例:编辑前备份(注意格式,-i 后面直接紧挨着指定后缀)
[root@centos8 ~]# cat seq.log
1
2
3
4
5
6
[root@centos8 ~]# sed -i.bak '2d;4d;5d' seq.log
[root@centos8 ~]# ll se*
-rw-r--r--. 1 root root 6 Aug 11 11:45 seq.log
-rw-r--r--. 1 root root 12 Aug 11 11:44 seq.log.bak #备份成功
[root@centos8 ~]# cat seq.log.bak
1
2
3
4
5
6
[root@centos8 ~]# cat seq.log
1
3
6
9范例:
#只显示非#开头的行
[root@centos8 ~]# sed -n '/^#/!p' /etc/fstab
UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0
UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2
UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0
UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0
#删除所有以#开头的行
[root@centos8 ~]# sed '/^#/d' fstab
UUID=3d1ad34e-cc80-4047-9167-474bd4dfc5a5 / xfs defaults 0 0
UUID=ed944ea3-8ecd-43f6-af42-b1da086e778c /boot ext4 defaults 1 2
UUID=8c8df88e-0a9e-494f-831f-8abffc065a4e /data xfs defaults 0 0
UUID=c47e4725-5b77-4d3f-8842-60e5689d45cc swap swap defaults 0 0
10范例:在匹配到的行上下插入新行,或替换之
sed'/root/a\superman' /etc/passwd 在匹配行的上一行插入新一行,内容为superman
sed '/root/i\superman' /etc/passwd 在匹配行的下一行插入新一行,内容为superman
sed '/root/c\superman' /etc/passwd 将匹配到的行内容替换为superman
11范例:批量删除指定行
sed '/^$/d' file 删除所有空行
sed '1,10d' file 删除1~10行
12范例:(nl命令对文本逻辑排序,显示行号)
[root@centos8 ~]# nl /etc/passwd|sed '2a \tea'
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
..........
[root@centos8 ~]# nl /etc/passwd|sed '2c tea' #省略斜线也可
1 root:x:0:0:root:/root:/bin/bash
tea
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
..........
搜索替换 s / / /
s/pattern/string/修饰符
查找替换,支持使用其它分隔符,可以是其它形式:s@@@,s###
替换修饰符:
g 行内全局替换
p 显示替换成功的行
#注意区别:命令p表示打印模式空间内容,此处s///占用了原来的p的位置和功能,因此作为补充,仍然是p
w /PATH/FILE 将替换成功的行保存至文件中
sed 's/test/mytest/g' example #也可表示为's/test/my&/'(而且是全局替换)
#将文件example全部内容中的test替换为mytest
以下两者每个匹配行只处理第一个root,全局处理需要再加g
sed -n 's/root/&superman/p' /etc/passwd
#表示对有root的行 的第一个root 后面追加superman
sed -n 's/root/superman&/p' /etc/passwd
#表示对有root的行 的第一个root 前面追加superman
sed -e 's/dog/cat/g' -e 's/hi/lo/g' pets
#将文件 pets 中的所有dog换为cat ,所有hi换为lo ,并输出编辑后的全文
sed -i.bak 's/dog/cat/g' pets
#将文件 pets 备份为pets.bak,且所有dog换为cat,并输出编辑后的全文
正则表达式的运用:
从命令 ip a 取IP地址:
'至少一个非数字,接(一个以上数字或.连续出现),接任意内容
[root@centos8 ~]#ip a | sed -nr "9s/[^0-9]+([0-9.]+).*/\1/p"
10.0.0.8
'以至少一个非数字开头,接(一个以上数字或.连续出现),接任意内容 此方法可简化为1
[root@centos8 ~]#ip a | sed -nr '9s/^[^0-9]+([0-9.]+).*$/\1/p'
10.0.0.8
最佳:'至少一个非数字,接(连续出现的7~15个数字或.),接任意内容
[root@centos8 ~]#ip a | sed -nr '9s/[^0-9]+([0-9.]{7,15}).*/\1/p'
10.0.0.8
'利用具体内容前后夹逼
[root@centos8 ~]#ip a | sed -nr '9s/(.*inet )([0-9].*)(\/.*)/\2/p'
10.0.0.8
'使用两次 s///的空白替换(删除)功能,前后夹逼删除
[root@centos8 ~]#ip a | sed -n '9s/.*inet //;9s/\/.*//p' #不必句首句尾锚定
10.0.0.8
[root@centos8 ~]#ip a | sed -n '9s/.*inet //p' | sed -n 's/\/.*//p' #管道后只剩一行,不需9s
10.0.0.8
取dirname和basename
'关键: [^/]+ 至少一个不是 / 开头的字符(从左往右抓)
[root@centos8 ~]# echo /etc/sysconfig/network-scripts/ | sed -nr 's#(^/.*/)([^/]+/?)#\1#p'
/etc/sysconfig/
[root@centos8 ~]# echo /etc/sysconfig/network-scripts/ | sed -nr 's#(^/.*/)([^/]+/?)#\2#p'
network-scripts/
取文件的前缀和后缀
'关键:后缀中没有 字符.
[root@centos8 ~]# echo a.c-d.345.gz|sed -nr 's/(.+)\.([^.]+)/\1/p'
a.c-d.345
[root@centos8 ~]# echo a.c-d.345.gz|sed -nr 's/(.+)\.([^.]+)/\2/p'
gz
'使用grep
[root@centos8 ~]# echo a.c-d.345.gz|grep -Eo '.*\.'
a.c-d.345. #不够完美
[root@centos8 ~]# echo a.c-d.345.gz|grep -Eo '[^.]+$'
gz
范例:去掉所有注释和空行
sed -r '/^(#|$)/d'
sed -r '/^#|^$/d'
范例:引用变量注意不能使用单引号
首先解释语法:
[root@centos8 ~]# sed "s/^/$RANDOM.rmvb/" 表示在stdin的前面添加"$RANDOM.rmvb"
AAAAAA
3272.rmvbAAAAAA
[root@centos8 ~]# echo | sed "s/^/$RANDOM.rmvb/"
30932.rmvb
[root@centos8 ~]# echo | sed 's/^/$RANDOM.rmvb/'
$RANDOM.rmvb