文本处理三剑客—“grep”
grep是Linux中最常用的“文本处理工具”之一,grep与sed、awk合称为Linux中的三剑客。
grep的全称为:Global search Regular Expression and Print out the line
全称中的“Global search”为全局搜索
全称中的“Regular Expression”表示正则表达式
即,grep是一个可以利用“正则表达式”进行“全局搜索”的工具,grep会在文本中按照指定的正则进行全局搜索,并将搜索出的行打印出来
当然,不通过正则表达式的方式也可以使用grep,但是当grep和正则表达式结合在一起时,功能威力更加强大
正则表达式,分为基本正则表达式和扩展正则表达式。
而grep默认支持基本正则表达式,不识别扩展正则表达式。如果想要令grep识别扩展正则表达式需要加上参数-E
关于正则表达式,可以参考以下博客:
https://www.cnblogs.com/Dlg-Blog/p/8733908.html
grep常用参数及搜索匹配模式
-i 忽略大小写
(如: grep -i root passwd 可以识别在passwd中的root,ROOT,Root,或root中任意字母大写的情况)
-n 显示匹配到的字符行在原文件中的行数
-2 显示匹配到的行的上下两行
-n2 显示搜到的结果的上下两行,并标示出行号
-A1 显示搜到的结果的下面一行
-B1 显示搜到的结果的上面一行
-E 用于识别扩展正则表达式,如:* (grep默认只支持基本正则表达式)
egrep == grep -E 这两条命令是等价的
-v 除了符合条件的被显示(不显示符合条件的,只显示不符合条件的)
grep -E "^root" passwd 显示在passwd文件中以root开头的行
grep -E "root$" passwd 显示在passwd文件中以root结尾的行
grep -Ei "^root|root$" passwd -v | grep root 显示在passwd文件中,root字符串在中间的行
(因为如果不二次过滤,不仅有root在中间的情况,还有不包含root的情况)
正规的 grep 不支持扩展的正则表达式, 竖线'|'是用于表示”或”的扩展正则表达式元字符 , 正规的 grep 无法识别。加上反斜杠 , 这个字符就被翻译成扩展正则表达式。
下图为例:
图一,二中,grep会将包含搜索关键词的行显示出来,并将关键词以红色字体显示
同时,grep默认是不支持*
这个通配符的,必须加上-E
参数才能识别,或者以\*
将*号转义,此时这只是一个符号,而不再指代任意个数的任意符号。
使用-i
参数,忽略匹配关键词中的大小写差异
图三中,grep -Ei "^root|root$" passwd -v | grep root
命令将显示root关键词在行中间部分的情况。我本来以为不需要-i参数就可以,但是实际操作中,不加该参数无法实现目标效果
图四中,由于一个匹配行是第一行,因此无法显示出其上面的行
grep中字符匹配
x..y #x和y之间有两个字符 .表示一个字符
x*y #表示x出现0-任意次(*之前的字符出现0-任意次)
x?y #出现0-1次
x+ #字符x出现1-任意次
x{n} #字符x出现n次,并解除贪婪模式,前后都不显示其他的
grep -E “\<x{1}y” westos #x至少出现一次,解除贪婪模式
grep -E “\xy{1}” westos #y至少出现一次,解除贪婪模式
grep -E “\(xy){1}” westos #xy至少出现一次,解除贪婪模式
x{m,n} #字符x至少出现m次,最多出现n次
x{m,} #字符x至少出现m次
x{,n} #字符x至多出现n次
解释:
grep x*y
相当于匹配y xy xxy xxxy ... 等等情况的合集
grep x?y
相当于匹配y xy两种情况的合集
grep x+y
相当于匹配xy xxy xxxy xxxxy等等情况的合集
注意:
grep使用的是贪婪模式
即,只要包含了搜索的字符,即便有多余的字符,也都会显示;而不是显示只含有关键词的行
\<关键字 左边除了关键字,不能有多余的字符
关键字\> 右边除了关键字,不能有多余的字符
\<关键字\> 除了关键字,不能有多余的字符
下图为例:
图一中,grep x*y file
搜索出的xyyyoo
这一结果,并不是匹配到xyyy
这个关键词,而是同时匹配到了xy y y
这三种情况。
文本处理三剑客—“sed”
sed,行编辑器,英文全称为:stream editor
用来操作纯 ASCII 码的文本,在处理时会把当前处理的行存储在临时缓冲区中 , 称为“模式空间” (pattern space) 可以指定仅仅处理哪些行
sed对于符合模式条件的行进行处理,不符合条件的不予处理
处理完成之后把缓冲区的内容送往屏幕输出显示,接着处理下一行 , 这样不断重复 , 直到文件末尾
调用sed命令有两种形式:
sed [options] ‘command’ file(s)
sed [options] -f scriptfile file(s)
-n 屏蔽模式空间里的数据(内存缓存空间中的数据)
p模式 显示,打印print
d模式 删除(不显示)
a模式 添加
i模式 插入
(a和i其实是一样的,只不过一个是在指定的行下面添加(a),一个是在指定的行上面添加(i))
c模式 修改
w模式 写入
(将sed命令操作的文本写入文件,根据操作实际修改文件本身,但是可能显示与文件的修改并不同)
sed处理文件文本时,会将该文件读入内存,模式空间
p,d,a等模式操作的是模式空间(内存中的文本),而不会更改原文件的内容
常用形式:
sed '/^UUID/p' fstab
显示文件fstab中以UUID开头的行,且会显示模式空间中的文本
(模式空间文本即整个fstab文件文本内容;因此UUID开头的行会显示两遍,模式空间中一遍,命令要求显示一遍)
sed '/^UUID/p' -n fstab
仅显示文件fstab中以UUID开头的行,不显示(屏蔽)模式空间中的文本
sed '1,4p' -n fstab
显示文件fstab中1-4行
sed '1p;4p' -n fstab
显示文件fstab中1行和第4行
(这其实就是两条命令了)
sed '/0$/p;/^7/p' -n fstab
显示文件fstab中以0结尾的行,和以7开头的行(行前不能有空格,否则会认为是以空格开头)
sed '/^#/d' fstab
将文件fstab中以#开头的行删除显示(d模式)
sed '/^#/!d' fstab
将文件fstab中除了以#开头的行删除显示(d模式)
(d模式不能加-n参数,否则没有显示内容)
sed '/^#/ahello\nwestos' fstab
在文件fstab中以#开头的行下面添加hello westos两行字符串显示(中间的\n转义字符表示换行符号)
sed '/^#/ihello\nwestos' fstab
在文件fstab中以#开头的行上面插入hello westos两行字符串显示
sed '/^#/chello westos' fstab
将文件fstab中以#开头的行更改为hello westos显示(c模式)
sed '/^#/w /mnt/westos' fstab
将文件fstab中以#开头的行写入文件/mnt/westos(应该使用相对路径也可以被识别)
sed -n '/^#/w /mnt/westos' fstab
将文件fstab中以#开头的行写入文件/mnt/westos
(但并不显示fstab文件内文本)
sed '/^#/=' fstab
将文件fstab中以#开头的行,每一行的前一行显示行号
(在文件整体中的行号,而不是所显示内容中的行序号)
sed '/^#/=' fstab > file1
将前一条命令的显示结果写入文件 ./file1
sed '/^#/=' -i file1
使用sed命令读取并操作file1文件,并将操作结果写入原文件
(-i参数向文件中写入,使用此参数更改原文件)
但是,注意:
不能写作如下形式
sed '/^#/=' file > file
无法用sed命令输出重定向将所操作的文件本身更新
sed '/^[[:digit:]]/d' fstab -i file1 (或者用[0-9]匹配数字)
将之前命令写入文件中的数字开头的行都删除
(-i参数向文件中写入,但是这个应该不是覆盖原文件写入,而是将在原文件基础上要做的操作写入)
sed '6r fstab' westos
将fstab文件插入westos的第6行下面显示(将两个文件合并显示)
sed '6r fstab' -i westos
将fstab文件插入westos的第6行下面显示,并写入westos
下图为例:
注意:
vim是交互模式的,但无法在脚本中调用vim更改配置文件内容
此时就可以使用sed命令在脚本中更改配置文件
sed的其他用法:
sed -e '/^UUID/p' -e '/UUID/=' fstab == sed '/^UUID/p;/UUID/=' fstab
-e参数的作用与分号;的作用相同,是令这两条命令分别执行的
sed -f rulefile fstab
将使用统一参数的多条sed命令的策略写入rulefile文件中
读取rulefile文件,使用该文件策略对fstab进行操作
(rulefile文件中写的就是sed命令中' '内的内容)
sed 's/#//g' file
将文件file中的所有行,所有列的#都替换为空
(相当于是vim file后,执行:s/#//g 详见我之前的vim操作的博客)
sed 's@#@@g' file
将文件file中的所有行,所有列的#都替换为空
即与上一条命令的功能完全相同,只是用@代替了/
sed '/2/,/4/s/#//g' file
将文件file中从字符串“2”所在行到字符串“4”所在行,所有列的#都替换为空
sed 'G' fstab
在fstab文件文本的每一行下加一空行
sed '$G' fstab
只在fstab文件文本的最后一行下加一空行
sed '$!G' fstab
在fstab文件文本的每一行下加一空行,但最后一行下面不加空行
sed '=' fstab
将fstab文件内容读取到内存模式空间中,将模式空间中的文本每一行前一行加上行号并显示
sed '=' fstab | sed 'N;s/\n//g'
清空fstab模式空间文本中的空行(将空行替换为无)
sed对于模式空间的内容是逐行读取的,因此想要去掉回车空行,将两行读取合并为一行,需要sed程序提前加载下一行的内容(因此下面的命令不行:sed '=' fstab | sed 's/\n//g')
N提前加载以下行的内容
sed -n ‘$p’ file
将file文件的最后一行($)打印显示出来(p)
下图为例:
文本处理三剑客—“awk”
awk是一个报告生成器,它拥有强大的文本格式化的能力
linux 上面默认使用 gawk
awk 处理机制 :awk 会逐行处理文本 , 支持在处理第一行之前做一些准备工作 , 以及在处理完最后一行做一些总结性质的工作 , 在命令格式上分别体现如下:
BEGIN{ }: 读入第一行文本之前执行 , 一般用来初始化操作
{ }: 逐行处理 , 逐行读入文本执行相应的处理 , 是最常见的编辑指令块
END{ }: 处理完最后一行文本之后执行 , 一般用来输出处理结果
awk常见用法:
awk '{print FILENAME}' passwd
(FILENAME不加‘’引号,会被识别为一个可用的变量;而加上引号会被识别为文本)
打印输出文件名,由于awk会逐行操作,对passwd文件的每一行操作
每操作一行,就会执行一次print操作,输出一次文件名;
因此,该命令最后输出多少行文件名,是要看文件本身有多少行
awk中默认变量NR,NF代表第几行,有多少列
(多少列的判定是根据分隔符决定的)
默认分隔符为空格
awk '{print NR}' passwd
打印输出passwd文件的行的序号
awk -F:'{print NF}' passwd
-F参数,指定分割符
以:作为分割符,统计passwd的每一行有多少列
awk -F : 'BEGIN{print “NAME”}{print "NR"}END{print "BYE"}' passwd
awk开始执行的时候显示“NAME”,再打印行的序号,执行结束后再打印“BYE“
awk -F : 'BEGIN{print “NAME”}{print $1}END{print "BYE"}' passwd
awk开始执行的时候显示“NAME”,再打印该行的变量$1的值,执行结束后再打印“BYE“
awk -F : 'BEGIN{print “NAME”}{print $1,$2}END{print "end"}' passwd
(或awk -F : 'BEGIN{print “NAME”}{print $1 $2}END{print "end"}' passwd)
awk -F : 'BEGIN{print “NAME”}{print $0}END{print "end"}' passwd
print $0 打印所有列($0所包含的所有的变量的值)
awk -F :'BEGIN{print “NAME”}{print $1="";print $0}END{print "end"}' passwd##打印第2行到第7行,$1=""相当于对第一列进行删除,但并不会改变原文件
注意的是,这样的命令不显示分割符,如果需要添加分隔符,需要添加
awk -F 'BEGIN{print “NAME”}{print $1="";print $0}END{print "end"}' passwd | sed 's/ /:/g'
该命令就是在上一命令的基础上加上了分割符:
awk '/bash$/{print}' passwd
打印以bash结尾的行
awk '!/bash$/{print}' passwd
打印除了以bash结尾的行以外的行
awk '/^root/ && /bash$/{print}' passwd
打印以root开头,同时以bash结尾的行
awk '/^root/ || /bash$/{print}' passwd
打印以root开头,或者以bash结尾的行
awk '!/bash$/&&!/nologin/{print}' passwd
打印不以bash结尾且不含有nologin的行
awk '/\<bash$/{print}' passwd
打印以bash结尾的行,并且解除关键词左侧的贪婪模式
awk 'BEGIN{n=0}/bash$/{n++}END{print n}' passwd
用变量n计算一共有多少行以bash结尾
(以bash结尾的行一共有多少行,去掉/bash$/可以用来计算该文件的总行数)
awk '/^[a-c]/{print}' passwd
打印以a,b,c开头的行
(筛选出以a,b或c开头的行,并将其打印出来)
awk -F : '$6~/bin/{print}' passwd
打印第六列中为bin的行,默认贪婪模式(如:sbin也会被匹配到)
(匹配$6变量的值,可以与bin字符串相匹配的行,并打印出来)
awk -F : '$6~/bin/{print}' passwd
打印第六列中bin的行
awk -F :'$6!~/\<bin\>/{print}' passwd
打印第6列不包含,不匹配bin的行,退出贪婪模式
awk -F :'!/nologin$/{print $1}' /etc/passwd
显示可以登录的用户的名称
(打印出不含nologin字符串的行的$1的值)
awk -F :'BEGIN{n=0}/bash$/&&$6!~/^\/home/{n++}END{print n}' passwd
统计可登录并且加目录不在/home下的用户
下图为例: