SHELL脚本编程之文本处理

  • 时间:
  • 来源:互联网
  • 文章标签:

SHELL脚本编程之文本处理

    • 文件处理三剑客之grep
        • grep命令
        • 语法格式
        • grep参数
        • grep和egrep
    • 文件处理三剑客之sed
        • sed工作模式
        • sed选项
        • sed中的pattern详解
        • sed中的编辑命令详解
        • 反向引用
        • 利用sed查找文件内容
        • 利用sed删除文件内容
        • 利用sed修改文件内容
        • 利用sed追加文件内容
    • 文本处理三剑客之awk
        • awk工作模式
        • awk内置变量
        • awk格式化输出之printf
        • awk模式匹配的两种用法
        • awk表达式用法
        • awk动作中的条件及循环语句
        • awk中的字符串函数
        • awk的常用选项
        • awk中数组的用法
        • 实例

文件处理三剑客之grep

grep命令

grep 命令用于查找文件里符合条件的字符串。

语法格式

语法1:
grep [option] [ pattern] [file1, file2..]
语法2:
command | grep [option] [pattern]

在这里插入图片描述

grep参数

选项含义
-v不显示匹配行信息
-i搜索时忽略大小写
-n显示行号
-r递归搜索
-E支持扩展正则表达式
-F不按正则表达式匹配,按照字符串字面意思匹配
-c只显示匹配行总数
-w匹配整词
-x匹配整行
-l只显示文件名,不显示内容
-s不显示错误信息

在这里插入图片描述

grep和egrep

  • grep默认不支持扩展正则表达式,只支持基础正则表达式
  • 使用grep-E可以支持扩展正则表达式使用
  • egrep可以支持扩展正则表达式,与grep-E等价
    在这里插入图片描述

文件处理三剑客之sed

sed工作模式

sed(Stream Editor),流编辑器。对标准输出或文件逐行进行处理

语法格式

语法一:
stdout |sed [option] "pattern command"

语法二:
sed [option] "pattern command" file

sed选项

选项含义
-n只打印模式匹配行
-e直接在命令行进行sed编辑,默认选项
-f编辑动作保存在文件中,指定文件执行
-r支持扩展正则表达式
-i直接修改文件内容

在这里插入图片描述 在这里插入图片描述
在这里插入图片描述

edit.sed文件写入:

/python/p

在这里插入图片描述

sed中的pattern详解

pattern用法表

匹配模式含义
10command匹配到第10行
10,20command匹配从第10行开始,到第20行结束10,
10,+5command匹配从第10行开始,到第16行结束
/pattern1/command匹配到pattern1的行
/pattern1/,/pattern2/command匹配到pattern1的行开始,到匹配到patern2的行结束
10,/pattern1/command匹配从第10行开始,到匹配到pettern1的行结束
/pattern1/,10command匹配到pattern1的行开始,到第10行匹配结束

实例

打印file文件的第17行
sed -n "17p" file

打印文件的10到20行
sed -n "10,20p" file

打印file文件中从第10行开始,往后面加5行
sed -n "10,+5p" file

打印file文件中以root开头的行
sed -n "/^root/p" file

打印file文件中第一个匹配到以ftp开头的行,到mail开头的行结束
sed -n "/^ftp/,/^mail/p" file

打印file文件中从第4行开始匹配,直到以hdfs开头的行结束
sed -n "4,/^hdfs/p" file

打印file文件中匹配root的行,直到第10行结束
sed -n "/root/,10p"file

sed中的编辑命令详解

编辑命令对照表

类别编辑命令含义
查询p打印
=只显示行号
增加a行后追加
i行前追加
r外部文件读入,行后追加
w匹配行写入外部文件
删除d删除
修改s/old/new将行内第一个old替换为new
s/old/new/g将行内全部的old替换为new
s/old/new/2g将行内从第2个old开始到剩下所有的old替换为new
s/old/new/ig将行内全部的old替换为new,忽略大小写

实例
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

反向引用

先看一下例子

在这里插入图片描述
&和\1引用模式匹配到的整个串
两者区别在于只能表示匹配到的完整字符串,只能引用整个字符串;而\1可以使用()匹配到的字符

sed中引用变量时注意事项:
(1)、匹配模式中存在变量,则建议使用双引号
(2)、sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号

#!/bin/bash

old_str=hadoop
new_str=HADOOP

sed -i "s/$old_str"/"$new_str/g" abc.txt

在这里插入图片描述

利用sed查找文件内容

需求描述:
处理一个类似MySQL配置文件my.cnf的文本,示例如下;编写脚本实现以下功能:输出文件有几个段,并且针对每个段可以统计配置参数总个数

my.cnf

# this is read by the standalone daemon and embedded servers
[client]
port=3306
socket=/tmp/mysql.socket

#ThisSegmentForserver
[server]
innodb_buffer_pool_size=91750M
innodb_buffer_pool_instances=8
innodb_buffer_pool_load_at_startup=1
innodb_buffer_pool_dump_at_shutdown=1
innodb_data_file_path=ibdata1:1G:autoextend
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=32M
innodb_log_file_size=2G
innodb_log_files_in_group=2
innodb_max_undo_log_size=4G
innodb_undo_directory=undolog
innodb_undo_tablespaces=95

#thisisonlyforthemysqldstandalonedaemon
[mysqld]
port=3306
socket=/tmp/mysql.sock
basedir=/usr/local/mysql
datadir=/data/mysql
pid-file=/data/mysql/mysql.pid
user=mysql
bind-address=0.0.0.0
sort_buffer_size=16M
join_buffer_size=16M
thread_cache_size=3000
interactive_timeout=600
wait_timeout=600

#ThisSegmentFormysqld_safe
[mysqld_safe]
log-error=/var/log/mariadb/mariadb.log
pid-file=/var/run/mariadb/mariadb.pid
max_connections=1000
open_files_limit=65535
thread_stack=512K
external-locking=FALSE
max_allowed_packet=32M

#thisisonlyforembeddedserver
[embedded]
gtid_mode=on
enforce_gtid_consistency=1
log_slave_updates
slave-rows-search-algorithms='INDEX_SCAN,HASH_SCAN'
binlog_format=row
binlog_checksum=1
relay_log_recovery=1
relay-log-purge=1


#usethisgroupforoptionsthatolderserversdon'tunderstand
[mysqld-5.5]
key_buffer_size=32M
read_buffer_size=8M
read_rnd_buffer_size=16M
bulk_insert_buffer_size=64M
myisam_sort_buffer_size=128M
myisam_max_sort_file_size=10G
myisam_repair_threads=1
lock_wait_timeout=3600
explicit_defaults_for_timestamp=1
innodb_file_per_table=1

预想输出结果:
1:client 2
2:server 12
3:mysqld 12
4:mysqld_safe 7
5:embedded 8
6:mysqld-5.5 10

脚本

#!/bin/bash

FILE_NAME=/root/Desktop/dir2/my.cnf

function get_all_segments
{
	echo "`sed -n '/\[.*\]/p' $FILE_NAME |sed -e 's/\[//g' -e 's/\]//g'`"
}



function count_items_in_segment
{
	
	echo "`sed -n '/\['$1'\]/,/\[.*\]/p' $FILE_NAME  | grep -v ^# |grep -v ^$ |grep -v "\[.*\]" |wc -l `"
}

num=0
for seg in `get_all_segments`
do
	num=`expr $num + 1`
	items_count=`count_items_in_segment $seg`
	echo "$num:$seg  $items_count"
done

在这里插入图片描述

利用sed删除文件内容

删除配置文件中的所有注释行和空行
sed -i '/[:blank:]*#/d;/^$/d' nginx.conf

在配置文件中所有不以#开头的行前面添加*符号,注意:以#开头的行不添加
sed -i 's/^[^#]/\*&/g' nginx.conf

利用sed修改文件内容

修改用法总结:

1、1s/old/new/

2、5,10s/old/new/

3、10,+10s/old/new/

4、/pattern1/s/old/new/

5、/pattern1/,/pattern2/s/old/new/

6、/pattern1/,20s/old/new/

7、15,/pattern1/s/old/new/

实例

修改/etc/passwd中第1行中第1个root为ROOT	
sed -i '1s/root/ROOT/' passwd

修改/etc/passwd中第5行到第10行中所有的/sbin/nologin为/bin/bash
sed -i '5,10s/\/sbin\/nologin/\/bin\/bash/g' passwd

修改/etc/passwd中匹配到/sbin/nologin的行,将匹配到行中的login改为大写的LOGIN
sed -i '/\/sbin\/nologin/s/login/LOGIN/g' passwd

修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内为将这些所有匹配到的行中的bin改为HADOOP
sed -i '/^root/,/mail/s/bin/HADOOP/g' passwd

修改/etc/passwd中从匹配到以root开头的行,到第15行中的所有行,修改内容为将这些行中的nologin修改为SPARK
sed -i '/^root/,15s/nologin/SPARK/g' passwd

修改/etc/passwd中从第15行开始,到匹配到以yarn开头的所有航,修改内容为将这些行中的bin换位BIN
sed -i '15,/^yarn/s/bin/BIN/g' passwd

利用sed追加文件内容

1、a					在匹配行后面追加		
2、i					在匹配行前面追加
3、r					将文件内容追加到匹配行后面
4、w					将匹配行写入指定文件	

实例

1、a	append
		
(1)、passwd文件第10行后面追加"Add Line Behind"		
sed -i '10a Add Line Begind' passwd
(2)、passwd文件第10行到第20行,每一行后面都追加"Test Line Behind"
sed -i '10,20a Test Line Behind' passwd
(3)、passwd文件匹配到/bin/bash的行后面追加"Insert Line For /bin/bash Behind"
sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd
		
2、i
		
(1)、passwd文件匹配到以yarn开头的行,在匹配行前面追加"Add Line Before"
sed -i '/^yarn/i Add Line Before' passwd
(2)、passwd文件每一行前面都追加"Insert Line Before Every Line"
sed -i 'i Insert Line Before Every Line' passwd
			
3、r
		
(1)、将/etc/fstab文件的内容追加到passwd文件的第20行后面
sed -i '20r /etc/fstab' passwd
(2)、将/etc/inittab文件内容追加到passwd文件匹配/bin/bash行的后面
sed -i '/\/bin\/bash/r /etc/inittab' passwd
(3)、将/etc/vconsole.conf文件内容追加到passwd文件中特定行后面,匹配以ftp开头的行,到第18行的所有行
sed -i '//,18r /etc/vconsole.conf' passwd
			
4、w
		
(1)、将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中
sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd
(2)、将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt
sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd
				

文本处理三剑客之awk

awk工作模式

awk是一个文本处理工具,通常用于处理数据并生成结果报告

awk 'BEGIN{} pattern{commands}END{}' file_name
standard output | awk 'BEGIN{}pattern{commands}END{}'

语法格式说明

语法格式解释
BEGIN{}正式处理数据之前执行
pattern匹配模式
{commands}处理命令,可能多行
END{}处理完所有匹配数据后执行

awk内置变量

内置变量含义
$0打印行所有信息
$1~$n打印行的第1到n个字段的信息
NFNumber Field 处理行的字段个数
NRNumber Row 处理行的行号,从1开始计数
FNRFile Number Row 多文件处理时,每个文件单独记录行号,都是从0康凯斯
FSField Separator 字段分割符,不指定时默认以空格或tab键分割
RSRow Separator 行分隔符,不指定时以回车分割\n
OFSOutput Filed Separator 输出字段分隔符。
ORSOutput Row Separator 输出行分隔符
FILENAME处理文件的文件名
ARGC命令行参数个数
ARGV命令行参数数组

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

awk格式化输出之printf

格式符

格式符含义
%s打印字符串
%d打印10进制数
%f打印浮点数
%x打印16进制数
%o打印8进制数
%e打印数字的科学计数法格式
%c打印单个字符的ASCII码
修饰符含义
-左对齐
+右对齐
#显示8进制在前面加o,显示16进制在前面加0x

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实例

1、以字符串格式打印/etc/passwd中的第7个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%s\n",$7}' /etc/passwd
			
2、以10进制格式打印/etc/passwd中的第3个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
			
3、以浮点数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd
			
4、以16进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
			
5、以8进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd
			
6、以科学计数法格式打印/etc/passwd中的第3个字段,以":"作为分隔符
			
awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd

awk模式匹配的两种用法

第一种
RegExp  按正则表达式匹配
第二种
关系运算匹配  按关系运算匹配

RegExp

匹配/etc/passwd文件行中含有root字符串的所有行

awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd

匹配/etc/passwd文件行中以yarn开头的所有行

awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd

运算符匹配

<			小于

>			大于

<=			小于等于

>=			大于等于

==			等于

!=			不等于

~			匹配正则表达式

!~			不匹配正则表达式

实例

以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息

awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd

以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息

awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息

awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd

以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息

awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd

以:为分隔符,匹配/etc/passwd中第3个字段包含3个以上数字的所有行信息

awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd


布尔运算符匹配:

||&&!

实例

以:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息

awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd

以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息

awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd

awk表达式用法

运算符含义
+
/
%
^或**乘方
++x在返回x变量之前,×变量加1
X++在返回x变量之后,×变量加1

实例

使用awk计算/etc/services中的空白行数量

awk '/^$/{sum++}END{print sum}' /etc/services

计算学生课程分数平均值,学生课程文件内容如下:
Allen 80 90 96 98
Mike 93 98 92 91
Zhang 78 76 87 92
Jerry 86 89 68 92
Han 85 95 75 90
Li 78 88 98 100

awk '{total=$2+$3+$4+$4;AVG=total/4;printf "%-8s%5d%5d%5d%5d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt

在这里插入图片描述

awk动作中的条件及循环语句

条件语句:

if(条件表达式1)
	动作
else if(条件表达式2)
	动作
else
	动作

以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息

awk 'BEGIN{FS=":"}{if($3<50){ printf "%-20s%-20s%-5d\n","小于50的UID",$1,$3} else if($3>100) {printf "%-20s%-20s%-5d\n","大 于100的UID",$1,$3} else{ printf "%-20s%-20s%-5d\n","大于50 小于100的UID",$1,$3}}' /etc/passwd

在这里插入图片描述
循环语句:

while循环:

while(条件表达式)
	动作
					
do while循环:
	do
		动作
	while(条件表达式)
				
for循环:
	for(初始化计数器;计数器测试;计数器变更)
		动作

实例:

计算1+2+3+4+…+100的和,请使用while、do while、for三种循环方式实现

while

BEGIN{
	while(i<=100) #不需要事先声明
	{
		sum+=i
		i++
	}
	print sum
}

for

BEGIN{
	for(i=0;i<=100;i++) #不需要事先声明
	{
		sum+=i
	}
	print sum
}

do while

BEGIN{
	do
	{
		sum+=i
		i++
	}while(i<=100)
	print sum
}

在这里插入图片描述

awk中的字符串函数

函数名解释
length(str)计算长度
index(str1,str2)返回在str1中查询到的str2的位置
tolower(str)小写转换
toupper(str)大写转换
split(str,arr,fs)分隔字符串,并保存到数组中
match(str,RE)返回正则表达式匹配到的子串的位置
substr(str,m,n)截取子串,从m个字符开始,截取n位。n若不指定,则默认截取到字符串尾
sub(RE,RepStr,str)替换查找到的第一个子串
gsub(RE,RepStr,str)替换查找到的所有子串

以:为分隔符,返回/etc/passwd中每行中每个字段的长度

root: x:0:0:root:/root:/bin/bash
4:1:1:1:4:5:9

BEGIN{
	FS=":"
	
}
{
	i=0
	while(i<=NF)
	{
		if(i==NF)
			printf "%d",length($i)	
		else
			printf "%d:",length($i)
		i++

	}
	print ""

}

在这里插入图片描述
搜索字符串"I have a dream"中出现"ea"子串的位置
awk 'BEGIN{str=“I hava a dream”;location=index(str,“ea”);print location}

awk ‘BEGIN{str=“I hava a dream”;location=match(str,“ea”);print location}’

将字符串"Hadoop is a bigdata Framawork"全部转换为小写
awk ‘BEGIN{str=“Hadoop is a bigdata Framework”;print tolower(str)}’

将字符串"Hadoop is a bigdata Framawork"全部转换为大写
awk ‘BEGIN{str=“Hadoop is a bigdata Framework”;print toupper(str)}’

将字符串"Hadoop Kafka Spark Storm HDFS YARN Zookeeper",按照空格为分隔符,分隔每部分保存到数组array中
awk ‘BEGIN{str=“Hadoop Kafka Spark Storm HDFS YARN Zookeeper”;split(str,arr," ");for(a in arr) print arr[a]}’

搜索字符串"Tranction 2345 Start:Select * from master"第一个数字出现的位置
awk ‘BEGIN{str=“Tranction 2345 Start:Select * from master”;location=match(str,/[0-9]/);print location}’

截取字符串"transaction start"的子串,截取条件从第4个字符开始,截取5位

awk ‘BEGIN{str=“transaction start”;print substr(str,4,5)}’

替换字符串"Tranction 243 Start,Event ID:9002"中第一个匹配到的数字串为$符号

awk ‘BEGIN{str=“Tranction 243 Start,Event ID:9002”;count=sub(/[0-9]+/,"$",str);print count,str}’

awk ‘BEGIN{str=“Tranction 243 Start,Event ID:9002”;count=gsub(/[0-9]+/,"$",str);print count,str}’

awk的常用选项

选项解释
-v参数传递
-f指定脚本文件
-F指定分隔符
-V查看awk的版本号

在这里插入图片描述

awk中数组的用法

shell中数组的用法:

打印元素:
echo ${array[2]}

打印元素个数:
echo ${#array[@]}

打印元素长度:
echo ${#array[3]}

给元素赋值:
array[3]="Li"

删除元素:
unset array[2];unset array

分片访问:
echo ${array[@]:1:3}

元素内容替换:
${array[@]/e/E}只替换第一个e;
$tarray[@]//e/E}替换所有的e

数组的遍历:
for a in array 
do
	echo $a 
done 

在这里插入图片描述
在这里插入图片描述

awk中数组的用法

在awk中,使用数组时,不仅可以使用1.2…n作为数组下标,也可以使用字符串作为数组下标

当使用1.2.3…n时,直接使用array[2]访问元素;需要遍历数组时,使用以下形式:

str="Allen Jerry Mike Tracy Jordan Kobe Garnet"
split(str,array," ")
for(i=1;i<length(array);i++)
	print array[i]

在这里插入图片描述
当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:

array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
	print array[a]

在这里插入图片描述

实例

  1. 统计主机上所有的TCP连接状态数,按照每个TCP状态分类
netstat -an | grep tcp | awk '{array[$6]++} END{for(a in array) print a,array[a]}'

在这里插入图片描述
2. 计算横向数据总和,纵向数据总和
allen 80 90 87 91
mike 78 86 93 96
Kobe 66 92 82 78
Jerry 98 74 66 54
Wang 87 21 100 43

BEGIN{ 
	printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","Yuwen","Math","English","Physical","Total"
}
{
	total=$2+$3+$4+$5
	yuwen_sum+=$2
	math_sum+=$3
	english_sum+=$4
	physical_sum+=$5
	printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,total
}
END{
	printf "%-10s%-10d%-10d%-10d%-10d\n","total",yuwen_sum,math_sum,english_sum,physical_sum
}

在这里插入图片描述

本文链接http://www.taodudu.cc/news/show-1782161.html