Linux文本处理三剑客

这篇博客介绍了Linux系统中常用的文本处理工具,包括grep、egrep、fgrep和sed。grep系列命令用于搜索文本,而sed采用流编辑模式,通过模式空间和保持空间处理文本,不会直接修改原文件。awk则是一种强大的文本分析工具。文章还提及了正则表达式的基础知识。

相关命令

grep命令

	print lines matching a pattern(打印与模式匹配的行)
	作用:文本过滤工具,根据用户指定的“模式”对目标文本逐行进行匹配检查,打印匹配到的行
	
	用法及常用选项:
		grep [OPTIONS] PATTERN [FILE...]    注意:模式两边要加引号
			选项:
				--color=auto:对匹配的文本着色显示
				-v:显示不能够被pattern(模式)匹配到的行
				-i:忽略字符大小写
				-o:仅显示匹配到的字符串
				-q:静默模式,不输出任何信息,只需要判断结果是否存在时会用到
				-A #:after,后#行;显示被匹配到的行后#行及被匹配到的行
				-B #:before,前#行;显示被匹配到的行前#行及被匹配到的行
				-C #:context,前后各#行;被匹配到行前后各#行及被匹配到的行
				-E:支持使用扩展的正则表达式
				-F:不使用正则表达式
				-P:使用prel正则表达式

egrep命令

支持扩展正则表达式实现类似于grep文本过滤功能;相当于grep -E
用法:grep [OPTIONS] PATTERN [FILE...]
选项:
	-i:忽略字符大小写
	-o:仅显示匹配到的字符
	-G:支持基本正则表达式

fgrep命令

不支持正则表达式元字符
当无需用到元字符去编写模式时,使用fgrep性能更好

sed命令

我们知道,vim 采用的是交互式文本编辑模式,你可以用键盘命令来交互性的插入、删除或替换数据中的文本。但这里讲的是 sed 命令不同,它采用的是流编辑模式,最明显的特点是,在 sed 处理数据之前,需要预先提供一组规则,sed 会按照此规则来编辑数据。

首先先讲讲sed的模式空间与保持空间
sed之所以能以行为单位的编辑或修改文本,其原因在于它使用了两个空间;一个是活动的“模式空间(pattern space)”,另一个是起辅助作用的“暂存缓冲区(holdingspace)”这两个空间的使用。
sed编辑器逐行处理文件,并将输出结果打印到屏幕上。sed命令将当前处理的行读入“模式空间”进行处理,sed在该行上执行完所有命令后将处理好的行打印到屏幕上(除非之前的命令删除了改行),sed处理完一行就将其从模式空间中删除,然后将下一行读入模式空间,进行处理、显示。处理完文件的最后一行,sed便结束运行。sed在临时缓冲区对文件进行处理,所以不会修改原文件,除非显示指明 -i 选项。

模式空间:可以想成工程里面的流水线,数据之间在它上面进行处理,用于处理文本行
保持空间:可以想象成仓库,我们在进行数据处理的时候,作为数据的暂存区域,用于保留文本行,是保存已处理过的文本行,默认有一个空行。

注意:保持空间中默认暂存一行空行

sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行输入,要么存储在一个文本文件中,此命令执行数据的顺序如下:
1.每次仅读取一行内容
2.根据提供的规则命令匹配并修改数据。注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区的数据
3.将执行结果输出
当一行数据匹配完成后,它会继续读取下一行数据,并重复这个过程,直到将文件中所有数据处理完毕。

sed 命令的基本格式如下:
	sed [OPTION]... 'SCRIPT' [input-file]...

	常用选项:
		-n:默认情况下,sed 会在所有的脚本指定执行完毕后,会自动输出处理后的内容,该选项不输出模式空间中的内容至屏幕
		-e SCRIPT:多点编辑(该选项将其后跟的脚本命令添加到已有的命令中(实现多个脚本命令))
			示例:sed -e 's@^#[[:space:]]*@@g' -e '/^UUID/d' /etc/fstab
		-f /PATH/TO/SED_SCRIPT_FILE:该选项会将其后文件中的脚本命令添加到已有的命令中
			每行一个编辑命令
		-r:支持使用扩展正则表达式
		-i [SUFFIX],--in-place[=SUFFIX]:直接编辑源文件

	地址定界:
		(1)空地址:对全文进行处理
		(2)单地址:
			#:指定行
			/pattern/:被此模式所匹配到的每一行
		(3)地址范围:
			#,#:起始行到结束行
			#,+#:起始行加多少行
			#,/pat1/:起始行至被pat1匹配到的行
			/pat1/,/pat2/:被第一个pat1模式所匹配到行至被被第一个pat2匹配到的行
			$:表示最后一行
		(4)步进地址:
			1~2:所有奇数行
			2~2:所有偶数行
	编辑命令:
		d:删除
		p:显示模式空间中的内容
		a \text:在被script所匹配到的行的下一行追加文本“text”,支持使用 \n 实现多行追加
		i \text:在被script所匹配到的行的上一行追加文本“text”,支持使用 \n 实现多行追加
		c \text:把匹配到的行替换为此处指定的文本“text”
		w /PATH/TO/SOMEFILE:保存模式空间匹配到的行至指定的文件中
		r /PATH.TO/SOMEFILE:读取指定文件的内容至当前文件被模式匹配到的行后面
		=:为模式匹配到的行打印行号(不过这个行号比较诡异,会占一行空间)
		!:条件取反;注意:放在模式的命令之前;
			地址定界!编辑命令
		s///:查找替换,其分隔符可自行指定,常用到的有 s@@@,s### 等
			替换标记:
				g:全局替换
				w /PATH/TO/SOMEFILE:将替换成功的结果保存至指定文件中
				p:显示替换成功的行

	高级编辑命令:
		h:把模式空间的内容覆盖至保持空间中
		H:把模式空间的内容追加至保持空间中
		g:把保持空间的内容覆盖至模式空间中
		G:把保持空间的内容追加至模式空间中
		n:覆盖读取匹配到的行的下一行至模式空间中
		N:追加读取匹配到的行的下一行至模式空间中
		d:删除模式空间中的行
		D:删除模式空间的所有行
		示例:
			sed -n 'n;p' FILE:显示偶数行
			sed '1!G;h$!d FILE:逆序显示文件内容
			sed '$!d' FILE:取出最后一行
			sed '$!N;$!D' FILE:取出最后两行
			sed '/^$/d;G' FILE:删除原有的所有空白行,而后为所有的非空白行后添加一个空白行
			sed 'n;d' FILE:显示奇数行
			sed 'G' FILE:在原有的每行后方添加一个空白行

练习1:删除/boot/grub/grub2.cfg文件中所有以空白字符开头的行的行首的所有空白字符
# sed 's@[[:space:]]\+@@' /boot/grub/grub.conf
练习2:删除/etc/fstab文件中所有以#开头的行的行首的#号及#号后面的所有空白字符
# sed 's@^#[[:space:]]*@@' /etc/fstab
练习3:输出一个绝对路径给sed命令,取出其目录,其行为类似于dirname
# echo "/var/log/messages" | sed 's@[^/]\+$@@'
# echo "/var/log/messages" | sed -r 's@[^/]+$@@'

awk命令

AWK是一种处理文本文件的语言,是一个强大的文本分析工具

gawk - pattern scanning and processing language (模式扫描及处理语言)

基本用法:gawk [options] 'program' FILE...
	program:PATTERN{ACTION STATEMENTS}
		语句之间用分号分隔
	
	选项:
		-F:指定输入时用到的字段分隔符(默认为空白字符)
			示例:-F:   #使用冒号为分隔符
		-v var=value:自定义变量

1、print
		print intem1,intem2
		要点:
			1.逗号分隔符
			2.输出的各item可以为字符串,也可以是数值;也可以是当前记录的字段、变量或awk的表达式
			(3)如省略item,相当于print $0($0表示整行内容)

2、变量
	2.1 内建变量
		FS:input field seperator,输入分隔符(默认为空白字符)
		OFS:output field seperator,输出分隔符(默认为空白字符)
		RS:input record seperator,输入的换行符(默认为$)
		ORS:output record seperator,输出的换行符
		NF:number of field,字段数量
			{print NF},{print $NF} 
		NR:number of record,行数
		FNR:各文件的分别计数,行数
		FILENAME:当前文件名
		ARGC:命令行参数的个数
		ARGV:数组,保存的是命令行所给定的各参数

	2.2 自定义变量
		(1)-v var=value
				变量名区分字符大小写
		(2)在program中直接定义

3.printf命令
	格式化输出:printf "FORMAT", tem1,intem2
		(1) FORMAT必须给出
		(2) 不会自动换行,需要显示给出换行控制符,\n
		(3) FORMAT中需要分别为后面的每个item指定一个格式化符号

		格式化:
			%c:显示字符的ASCII码
			%d或%i:显示十进制整数
			%e或%E:科学计数法数值显示
			%f:显示为浮点数
			%g或%G:以科学计数法或浮点形式显示数值
			%s:显示字符串
			%u:无符号整数
			%%:显示%自身
		修饰符:
			#[.#]:第一个数字控制显示的宽度;第二个#表示小数点后的精度
				示例:%3.1f
			-:表示左对齐
			+:显示数值的符号
		
4.操作符
	算数运算操作符
		x+y,x-y,x*y,x/y,x^y,x%y
		-x:负值	
		+x:转换为数值

	字符串操作符:没有符号的操作符,字符串连接
	
	赋值操作符:
		=,+=,-=,*=,/=,%=,^=
		++,--
	比较操作符:
		>,>=,<,<=,!=,==
	模式匹配符:
		A~/PATTERN:判断字符串A中是否包含能匹配B表达式的子字符串
		A!~B:判断字符串A中是否不包含能匹配B表达式的子字符串
	
	逻辑操作符:
		&&
		||
		!

	函数调用:
		function_name(argu1,argu2,...)
	条件表达式:
		selector?if=ture-expression:if-false-expression
		示例:awk -F: '{$3>=1000?usertype="common user":usertype="sysadin";printf "%15s:%-s\n,$1,usertype}' /etc/passwd

	PATTERN
		(1) empty:空模式,匹配每一行
		(2) /regular expression/:仅处理能够被此处的模式匹配到的行
		(3) relational expression:关系(比较)表达式:结果有“真”有“假”;结果为“真”才会被处理
			真:结果为非0值,非字符串
		(4) line ranges:行范围
			startline,endline:/part1/,/pat2/
			注意:不支持直接给出数字格式
			awk -F: 'NR>=2&&NR<=10{print $1}' /etc/passwd
		(5) BEGIN/END模式
			BEGIN{}:仅在开始处理文件中的文本之前,尚未读取任何数据之前,执行一次
			END{]:仅在文本处理完成之后执行一次

	常用的action:
		(1) Expressions(表达式)
		(2) Control statements(控制语句):if,while等
		(3) Compound statements:组合语句
		(4) input statements
		(5) output statements

	控制语句
		if(condition) {statements}
		if(condition) {statements} else {statements}
		while(condition) {statements}
		do {statements while(condition)
		for(expr1;expr2;expr3) {statements}
		berak
		continue
		delete array[index]
		delete array
		exit
		{statements}

		(1) if-else
			语法:if(condition) statement [else statement]
				示例:awk -F: '{if($3>=1000) {printf "Common user: %s\n",$1} else {printf "root or sysuer: %s\n",$1}}' /etc/passwd
				awk -F" " '{if(NF>5) print $0}' /etc/fstab
				df -h | awk -F[%] '/^\/dev/{print $1}' | awk '{if($NF>=20) print$1}'
				使用场景:对awk取得的整行或某个字段做条件判断
		
		(2) while循环
			语法:while(condition) statement
			条件为“真”进入循环,条件为“假”退出循环
			使用场景:对一行内的多个字段逐一类似处理时使用;对数组中的各元素逐一处理时使用
			length(item):显示某item的字符个数
			示例:
				(1) awk '/^[[:space:]]*linux16/(i=1;while(i<=NF) {print $i,length($i);i++}}' /etc/grub2.cfg
				(2) awk '/^[[:space:]]*linux16/{i=1;while(i<=NF) {if(length($i)>=7){print $i,length($i)};i++}}' /etc/grub2.cfg
		(3) do-while循环
			语法:do statement while(condition)
			意义:至少循环一次循环体

		(4) for循环
			语法:for(expr1;expr2;expr3) statement
			expr:控制变量初始化;条件判断表达式;控制变量修正表达式;
			for(variable_assignment;condition;interation_process) {for-body}
			示例:
				(1)awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++);{print $i,length($i)}}' /etc/grub2.cfg
				(2)awk '/^[[:space:]]*linux16/{for(i=1;i<=NF;i++) {if(length($i)>=7){print $i,length($i)}}}' /etc/grub2.cfg
			特殊用法:能够遍历数组中的元素
				语法:for(var in array) {for-body}
				
		(5)switch语句
			语句:switch(expression) {case VALUE1 or /REGEXP/: statement;case VLUE2 or /REGEXP2/: statement; ...; default: statement}
		(6)break和continue
			break [n]:可以跳出当前循环或n层循环
			continue:提前结束本轮循环直接进入下一轮循环
		(7)next
			控制awk的内生循环(行之间)
			(能提前结束本行的处理而直接进入下一行)
				提前结束对本行的处理而直接进入下一行
				示例:
					awk -F: '{if($3%2!=0)next;print $1,$3}' /etc/passwd
		(8)array(数组)
			关联数组:array_name[index-expression]
				index-expression:
					(1)可使用任意字符串;字符串要使用双引号
					(2)如果某数组元素事先不存在,在引用时,awk会自动创建此元素,并将其值初始化为“空串”
					若判断数组中是否存在某元素,要使用“index in array”格式进行
						weekdays["mon"]="Monday"
				若要遍历数组中的每个元素,要使用for循环
					for(var in array) {for-body}
					示例:
						awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";for(i in weekdays) print weekdays[i]}'
						注意:var会遍历array的每个索引
						netstat -tan | awk '/^tcp\>/{state[$NF]++}END{for(i in state) print i,state[i0]}'
						awk '{ip[$1]++}END{for(i in ip) print i,ip[i]}' /var/log/httpd
					练习:统计/etc/fstab文件中每个文件系统类型出现的次数
					awk '/^UUID/{fs[$3]++}END{for(i in fs) print i,fs[i]}' /etc/fstab
					练习:统计指定文件中每个单词出现的次数
					awk {for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count) print i,count[i]}' /etc/fstab
		(9)函数
			内置函数
			数值处理:
				rand():返回0和1之间的一个随机数
			字符串处理:
				length([s]):返回指定字符串的长度
				sub(r,s,[t]:以r表示的模式来查找t所表示的字符串中匹配的内容,并将其第一次出现替换为s所表示的内容
				gsub(r,s[t]):以r表示的模式来查找t所表示的字符串中匹配的内容,并将其所有出现替换为s所表示的内容
				split(s,a,[r]):以r为分隔符切割字符串s,并将切割后的结果保存至a所表示的数组中
				示例:netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
			自定义函数

基本正则表达式

字符匹配:
	. :点好表示匹配任意单个字符
	[]:匹配指定范围内的任意单个字符
	[^]:匹配指定范围外的任意单个字符
	[[:upper:]]:表示任意单个大写字母
	[[:lower:]]:表示任意单个小写字母
	[[:alpha:]]:表示任意单个所有字母,相当于[a-z]、[A-Z]
	[[:digit:]]:所有任意单个数字
	[[:alnum:]]:所有任意单个字符或数字
	[[:space:]]:任意单个空白字符
	[[:punct:]]:任意单个标点符号
	[^[:upper:]]:取反,匹配大写字符以外的任意字符和数字
	[^0-9]:匹配0-9数字以外的任意单个字符
	
匹配次数:用在要指定其出现的次数的字符的后面,用于限制其前面的字符出现的次数
	*:匹配其前面的字符任意次;0次;1次;多次
	.*:匹配任意长度的任意字符
	\?:匹配其前面的字符0次或1次;即其前面的字符可有可无
	\+:匹配其前面的字符1次或多次;即其前面的字符至少要出现一次
	\{m\}:匹配其前面的字符m次
	\{m,n\}:匹配其前面的字符至少m次,至多n次
	\{0,n\}:匹配其前面的字符至多n次,至少不限
	\{m,\}:匹配其前面的字符至少m次,至多不限
	
位置锚定:
	^:行首锚定;用于pattern(模式)的最左侧
	$:行尾锚定;用于pattern(模式)的最右侧
	^PATTERN$:用于PATTERN来匹配整行
	^$:空白行
	^[[:space:]]*$:空白行或包含空白行字符的行
	
	单词:非特殊字符组成的连续字符(字符串)都称为单词
	\<或\b:词首锚定;用于单词模式的左侧
	\>或\b:词尾锚定;用于单词模式的右侧
	\<PATTERN\>:匹配完整单词
	
分组及引用:
	\(\):将一个或多个字符捆绑在一起,当做一个整体进行处理
		\(xy\)*ab
	Note:分组括号中的模式匹配到的内容会被正则表达式引擎自动记录于内部的变量中,这些变量为:
		\1:模式从左侧起,第一个左括号以及与之匹配的右括号之间的模式所匹配到的字符
		\2:
		\3:
		...
		后向引用:引用前面的分组括号中的模式所匹配到的字符(而非模式本身)

扩展正则表达式

字符匹配:
	. :点号表示任意单个字符
	[]:指定范围内的任意单个字符
	[^]:指定范围外的任意单个字符

次数匹配:
   *:匹配其前面的字符任意次数,0次,1次,多次
   ?:匹配其前面的字符0次或一次;即其前面的字符可有可无
   +:匹配其前面的字符至少匹配一次
   {m}:匹配其前面的字符m次
```{m,n}:匹配其前面的字符至少m次,至多n次

位置锚定:
   ^:行首锚定;用于pattern最左侧
   $:行尾锚定;用于pattern最右侧
   \<或\b:词首锚定
   \>或\b:词尾锚定

分组及引用:
   ():分组;括号内的模式匹配到的字符会被记录于正则表达式引擎内嵌的变量中
   后向引用:\1,\2,...

或:
   a | b:a或者b
   	C | cat:C或cat
   	(C|c)at:cat或Cat
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值