Shell编程之文本处理
2021/11/23 7:10:28
本文主要是介绍Shell编程之文本处理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
你必须非常努力,才能看起来毫不费力!
微信搜索公众号[ 漫漫Coding路 ],一起From Zero To Hero !
前言
在日常工作学习中,不免经常要对文本文件(例如日志文件)进行处理工作,包括但不限于分割、查找、替换、删除等操作,Shell
中有没有相应的命令供我们使用呢?那么本篇文章,我们就一起来学习下吧!
cut
grep
命令可以查找文件中符合条件的行,cut
命令则可以根据分隔符,提取行中的列,默认分隔符为 TAB
。
# cut [选项] 文件名 选项 -f 列号: 提取第几列 -d 分隔符: 按照指定分隔符分割列 # cut默认分隔符是TAB
测试一下这个命令就容易理解了。我们首先新建一个文件,然后使用 TAB
分隔,然后使用 cut
命令提取列。
示例一
[root@VM-0-5-centos ~]# vim student.txt ID NAME Gender MARK 1 zs M 98 2 ls F 99 # 1. 提取第二列 [root@VM-0-5-centos ~]# cut -f 2 student.txt NAME zs ls # 2. 提取第二列和第四列 [root@VM-0-5-centos ~]# cut -f 2,4 student.txt NAME MARK zs 98 ls 99 # 3. 测试使用分隔符提取列 # 3.1 这是我们需要处理的文本 [root@VM-0-5-centos ~]# cat /etc/passwd | grep /bin/bash | grep -v root lifelmy:x:1000:1000::/home/lifelmy:/bin/bash user1:x:1001:1001::/home/user1:/bin/bash user3:x:1002:1003::/home/user3:/bin/bash # 3.2 提取第一列 [root@VM-0-5-centos ~]# cat /etc/passwd | grep /bin/bash | grep -v root | cut -f 1 -d : lifelmy user1 user3
从上面的例子我们可以看出,cut
命令可以提取行中的列,但是 cut
命令有一个缺点,就是分隔符的长度必须一致。如果列与列之间,有的是一个空格符,有的是两个空格符的话,cut
命令就不能正确划分列了。
示例二
[root@VM-0-5-centos ~]# df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 909M 0 909M 0% /dev tmpfs 919M 24K 919M 1% /dev/shm tmpfs 919M 540K 919M 1% /run tmpfs 919M 0 919M 0% /sys/fs/cgroup /dev/vda1 50G 5.6G 42G 12% / tmpfs 184M 0 184M 0% /run/user/0 # 使用 空格 作为分隔符,查出第一列 [root@VM-0-5-centos ~]# df -h | cut -f 1 -d " " 文件系统 devtmpfs tmpfs tmpfs tmpfs /dev/vda1 tmpfs # 但是查第二列的时候,得到的都是空格,不是我们想要的"容量"那一列 [root@VM-0-5-centos ~]# df -h | cut -f 2 -d " "
awk
从上面的示例二可以看出,cut
还是有些缺点的,那么这个问题有没有其他命令可以解决呢,这就轮到我们的 awk
命令出场了。在详细介绍 awk
命令前,我们先来看一下标准输出命令。
在awk命令的输出中支持 print
和 printf
命令
-
print: print会在每个输出之后自动加入一个换行符(Linux默认没有print命令)
-
printf: printf是标准格式输出命令,并不会自动加入换行符,如果需要换行,需要手动加入换行符
printf
printf "输出类型 输出格式" 输出内容 [输出类型]: %ns: 输出字符串,n表示输出几个字符 %ni: 输出整数,n表示输出几个数字 %m.nf: 输出浮点数,m、n分别表示输出的位数以及其中的小数位数. %8.2f表示共输出8位数,其中2位是小数,6位整数 [输出格式]: \a: 输出警告声音 \b: 输出退格键 \f: 清除屏幕 \n: 换行 \r: 回车 \t: 水平输出制表符 \v: 垂直输出制表符
示例
# %-5s 格式为左对齐且宽度为5的字符串代替('-'表示左对齐),不使用则默认右对齐。 # %-4.2f 格式为左对齐宽度为4,保留两位小数。 [root@VM-0-5-centos ~]# printf "%-5s %-10s %-4s\n" NO Name Mark NO Name Mark [root@VM-0-5-centos ~]# printf "%-5s %-10s %-4.2f\n" 01 Tom 90.3456 01 Tom 90.35 [root@VM-0-5-centos ~]# printf "%-5s %-10s %-4.2f\n" 02 Jack 89.2345 02 Jack 89.23 [root@VM-0-5-centos ~]# printf "%-5s %-10s %-4.2f\n" 03 Jeff 98.4323 03 Jeff 98.43 [root@VM-0-5-centos ~]# printf '%d %d %d\n' 12 34 56 12 34 56
awk
是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。
awk 'BEGIN{动作} 条件1{动作1} 条件2{动作2} END{动作}' file 条件(Pattern): 一般使用关系表达式作为条件 x>10 x<=10 动作(Action): 格式化输出 流程控制语句
一个awk脚本由三部分组成:BEGIN语句块、能够使用条件匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中。
BEGIN条件,会在读取文件第一行之前执行相应的动作;END条件,读取完文件后执行。
测试
# 1. 在处理第一行文件时先执行BEGIN对应的动作,然后无条件对每一行使用默认的空格分隔后取出第5列,最后执行 END 对应的动作 [root@VM-0-5-centos ~]# df -h | awk 'BEGIN{printf "this is begin \n"} {printf $5 "\n"} END{printf "this is end \n"}' this is begin 已用% 0% 1% 1% 0% 12% 0% this is end # 2. 在处理第一行文件前赋值 i=0,然后每处理一行就将i加一,最后输出i的值 [root@VM-0-5-centos ~]# df -h | awk 'BEGIN{ i=0 } { i++ } END{ print i }' 7 # 3. 将1、2两个例子结合起来 [root@VM-0-5-centos ~]# df -h | awk 'BEGIN{i=0 ;printf "start \n"} {printf $5 "\t"} {i++; printf i "\n"} END{printf "end\n"}' start 已用% 1 0% 2 1% 3 1% 4 0% 5 12% 6 0% 7 end
由于 awk
命令的默认分隔符是空格(没有数量限制),因此对于分隔符不是空格的文件来说,BEGIN
的主要作用就是在处理文件前设置分隔符,其中FS
用来设置分隔符。
# 要处理的数据 [root@VM-0-5-centos ~]# cat /etc/passwd | grep syslog syslog:x:996:994::/home/syslog:/bin/false # 使用 BEGIN 设置分隔符为":",然后输出第三列数据 [root@VM-0-5-centos ~]# cat /etc/passwd | grep syslog | awk 'BEGIN {FS=":"} {printf $3 "\n"}' 996 # 使用关系运算符条件 [root@VM-0-5-centos ~]# cat /etc/passwd | awk 'BEGIN {FS=":"} $3>995{printf $3 "\n"}' 999 998 997 996 1000 1001 1002
下面给出一个具体问题,思考下你会怎么处理。上面我们已经使用过了 df -h
命令,该命令是用于查看Linux的磁盘占用情况,我们想要设置个定时任务,每天去检查某个磁盘的占用情况,如果磁盘占用比例到了80%,就发送邮件报警。这里我们只处理第一步,就是判断磁盘占用情况是否超出了设置的阈值。
脚本文件
#!/bin/bash read -p 'please input rate: ' r rate=$(df -h | grep 'vda1'| awk '{printf $5}' | cut -d '%' -f 1) if [ $rate -gt $r ] then echo 'alarm' fi
测试
[root@VM-0-5-centos ~]# chmod 755 test.sh [root@VM-0-5-centos ~]# ./test.sh please input rate: 20 [root@VM-0-5-centos ~]# ./test.sh please input rate: 10 alarm
sed
sed
是一种几乎包括所有unix平台(包括Linux)的轻量级流编辑器,它是文本处理中非常重要的工具,能够完美的配合正则表达式使用,功能不同凡响。
处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用 sed
命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。sed
主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。
# sed [选项] '动作' 文件名 选项: -n 一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕 -e 允许对输入数据应用多条sed命令编辑 -i 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出 动作: a: 追加,在当前行后添加一行或多行。添加多行时,除最后一行外,每行末尾需要用'\' 代表数据未完结 c: 行替换,用'c' 后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾用'\' 表示数据未完结 i: 插入,在当前行前插入一行或多行。插入多行时,除最后一行外,每行末尾用'\' 表示数据未完结 d: 删除,删除指定的行 p: 打印,输出指定的行 s: 字符串替换,用一个字符串替换另一个字符串。格式为 "第几行s/旧字串/新字串/g",使用 '/g'表示替换该行中的所有匹配 (与vim类似)
测试
# 要处理的文件 [root@VM-0-5-centos ~]# cat student.txt ID NAME Gender MARK 1 zs M 98 2 ls F 99 # 打印输出第2行,默认不仅会输出指定的行,还会输出原有文件中的所有行 [root@VM-0-5-centos ~]# sed '2p' student.txt ID NAME Gender MARK 1 zs M 98 1 zs M 98 2 ls F 99 # -n,只输出sed处理的数据 [root@VM-0-5-centos ~]# sed -n '2p' student.txt 1 zs M 98 # 删除第2行的数据,但不修改原文件 (在缓冲区修改的) [root@VM-0-5-centos ~]# sed '2d' student.txt ID NAME Gender MARK 2 ls F 99 [root@VM-0-5-centos ~]# cat student.txt ID NAME Gender MARK 1 zs M 98 2 ls F 99 # 在第3行后追加一条数据,不修改原数据 (在缓冲区修改的) [root@VM-0-5-centos ~]# sed '3a hello world' student.txt ID NAME Gender MARK 1 zs M 98 2 ls F 99 hello world # 在第3行前插入一条数据,不修改原数据 (在缓冲区修改的) [root@VM-0-5-centos ~]# sed '3i hello world' student.txt ID NAME Gender MARK 1 zs M 98 hello world 2 ls F 99 # 替换第3行的数据,不修改原数据 (在缓冲区修改的) [root@VM-0-5-centos ~]# sed '3c hello world' student.txt ID NAME Gender MARK 1 zs M 98 hello world # 替换字符串字段,不修改原数据 (在缓冲区修改的) [root@VM-0-5-centos ~]# sed '2s/98/100/g' student.txt ID NAME Gender MARK 1 zs M 100 2 ls F 99 # 字符串替换,直接修改文件 [root@VM-0-5-centos ~]# sed -i '2s/98/100/g' student.txt [root@VM-0-5-centos ~]# cat student.txt ID NAME Gender MARK 1 zs M 100 2 ls F 99 # 替换多处 [root@VM-0-5-centos ~]# sed -i '2s/M/F/; 2s/zs/ww/' student.txt [root@VM-0-5-centos ~]# cat student.txt ID NAME Gender MARK 1 ww F 100 2 ls F 99
总结
本篇文章一共学习了三个命令:
-
cut:用于提取一行文本中的列,默认分隔符是
TAB
,同时也可以指定分隔符。如果分隔符是空格,需要保证每列之间的空格数相同; -
awk:一种编程语言,功能强大,支持数组、函数等,类似 C语言;
-
sed:功能强大的流式文本编辑器,可以很方便的处理文件中的每一行数据。
PS:本文只是简单的介绍了命令的常用部分,如果想要更加深入了解,可以去这里学习。
更多
个人博客: https://lifelmy.github.io/
微信公众号:漫漫Coding路
这篇关于Shell编程之文本处理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-16Maven资料入门指南
- 2024-11-16Maven资料入门教程
- 2024-11-16MyBatis Plus资料:新手入门教程与实践指南
- 2024-11-16MyBatis-Plus资料入门教程:快速上手指南
- 2024-11-16Mybatis资料入门教程:新手必看指南
- 2024-11-16MyBatis资料详解:新手入门与初级实战指南
- 2024-11-16MyBatisPlus资料:初学者入门指南与实用教程
- 2024-11-16MybatisPlus资料详解:初学者入门指南
- 2024-11-16MyBatisX资料:新手入门与初级教程
- 2024-11-16RESTful接口资料详解:新手入门指南