Linux之旅 9:正则表达式与文件格式化

本文介绍了Linux中的正则表达式基础及扩展语法,包括grep和sed的使用,以及文件格式化工具printf、awk和档案比对工具如diff、cmp、patch的应用。正则表达式在字符串匹配、数据处理等方面发挥重要作用,通过学习和实践,可以提高Linux系统的文件管理和数据操作效率。
摘要由CSDN通过智能技术生成

Linux之旅 9:正则表达式与文件格式化

常用正则表达式

(图片来自常用正则表达式

什么是正则表达式

正则表达式(简称为正则)可以看做是一种微型标记语言,通过定义一系列符号来灵活地设定一种匹配模式,对目标字符串进行匹配,匹配出你想要获取的部分,然后进行下一步处理。

其目的相当明确,就是字符串匹配,当然,往往使用正则的程序也会在匹配的基础上提供替换或者删除的功能,但那些都可以看做是通过正则匹配出结果之后的动作。

我在前边说了,通配符通常可以看做一个精简版的正则,因为他们的目的相同,都是设定一个匹配模式进行匹配,不过前者要简单的多,而后者有完整而复杂的语义,老实说,初学者要把正则搞明白并不是件容易的事。

正则有什么用

但是正则的确相当有用,如果使用正则你会省不少事,比如说网页编程最常见的,需要判断某个输入框的合法性,是不是合法的电话,是不是合法的身份证,等等,如果从头开始编写一个字符串判断和处理的函数简直不可想象,而如果你懂正则,只需要按一定规则编写一段正则表达式即可,或者更多的是去网上copy一段。

再比如我经常用的一个小工具EasyPub,可以将txt电子书转换为kindle的专有格式mobi,转换的时候可以自动识别章节进行切割,但是有时候有些txt章节并非常见的第一章 xxx,而是### 1 xxx ###,默认的章节分割就不好使了,但庆幸的是该工具支持正则表达式切割章节,只要你会正则,只要txt中的章节标题都有迹可循,任何内容都不在话下。

如何学习

本篇文章的切入点是从Bash中支持正则表达式的命令入手,介绍一些简单的正则表达式在Bash命令中的实际使用,如果想系统地学习正则,各大厂商都有自己的正则教程或者参考手册,可以挑一个自己喜欢的:

如果想检查自己写的正则哪里出错了,可以使用这个工具debuggex

基础正则表达式

正则表达式的语法分为基础部分和扩展部分(可以看做是高级语法),虽然说我使用过的大部分主流编程语言,如javascriptJavaPHPPython中都支持完整的正则语法,但是Linux中某些应用,比如grep仅支持基础语法,扩展语法需要使用额外参数grep -E才能支持。所以这里关于正则表达式的语法介绍也分为基础和扩展两部分。

编码对正则表达式的影响

正则的某些语法是和具体编码直接相关的,比如[a-z],指的是编码表上从a字符到z字符的所有字符中的某一个。在标准的ASCII编码中,其范围自然是全部的小写字母,因为ASCII中小写字母是连续的(对应编号为97~122),相应的,对于兼容ASCII的字符集也会是相同的结果,比如各种UTF-8编码。但如果你使用的是某个不兼容ASCII的字符集,比如big5这种繁体字字符集,其编码的顺序是:

0 1 2 3 4 ... a A b B c C d D ... z Z

如果在这种编码下使用正则,[a-z]的范围就会变成a A b B c C d D ... z,显然是不正确的。

关于更多ASCII字符集的内容,可以阅读ASCII

幸运的是GB2312或者big5这些不兼容ASCII的老式编码现在已经越来越少用了,从操作系统到应用都越来越多地使用UTF-8这种新一代统一规范且兼容ASCII的编码,所以我们大部分时间都无需对此担心。

除了使用[a-z]这种方式指定小写字母,还可以使用一些正则预定义的符号集:

特殊字符 定义
[:lower:] 小写字母(Lower-case letters),即a-z
[:upper:] 大写字母(Upper-case letters),即A-Z
[:alpha:] 所有字母,即a-zA-Z(可能有人知道Google的母公司叫alphabet,即字母表,那么alpha的意思就是字母)
[:digit:] 数字,即0-9
[:alnum:] 字母和数字(即alpha+number的意思)
[:blank:] 空白符(blank characters),包含空格与制表符
[:cntrl:] 键盘上的控制按键,包括CR, LF, Tab, Del
[:punct:] 标点符号(Punctuation characters),比如\# $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ' { |} ~
[:graph:] 图形字符(Graphical characters),包括[:alnum:][:punct:],也就是字母数字和标点符号(可以理解为有图形的字符(相对于空白符等),对于UTF字符集来说可能会包含一些奇奇怪怪的字符,比如笑脸或者象棋棋子)
[:print:] 可打印字符(Printable characters),包括[:alnum:][:punct:]和空格
[:space:] 空格符(Space characters),包括制表符、换行符、垂直制表符、换页、回车、空格
[:xdigit:] 16进制数字(Hexadecimal digits),包括0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f

需要说明的是,这些特殊字符之所以能使用,是因为字符集本身会自带一个数据库,在数据库中标记哪些字符属于数字,哪些字符属于字母,哪些又是可打印的,诸如此类,所以实际使用效果根据字符集的不同可能会有不同的结果。

因为上边的原因,使用特殊字符相对于0-9a-z这样的写法有个额外的好处,即就算当前字符集中小写字母不是连续编码,中间插入了大写字母,也不会影响使用特殊字符(比如:lower:)的匹配结果。

grep的一些进阶选项

之前我们介绍过grep的一些用法,可以正选或者反选出匹配的行,此外,grep还可以打印匹配结果的行号:

[icexmoon@xyz ~]$ dmesg | grep -n ens33
1821:[   19.585777] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
1822:[   19.620521] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
1828:[   21.601791] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
1829:[   21.608352] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
1830:[   21.708661] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None

甚至可以额外打印出匹配结果的上下文:

[icexmoon@xyz ~]$ dmesg | grep -n ens33 -A 2 -B2
1819-[   16.342351] Bluetooth: BNEP socket layer initialized
1820-[   19.334452] ip6_tables: (C) 2000-2006 Netfilter Core Team
1821:[   19.585777] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
1822:[   19.620521] IPv6: ADDRCONF(NETDEV_UP): ens33: link is not ready
1823-[   19.626516] Ebtables v2.0 registered
1824-[   19.820016] Netfilter messages via NETLINK v0.30.
--
1826-[   20.609962] nf_conntrack version 0.5.0 (7778 buckets, 31112 max)
1827-[   21.259096] bridge: filtering via arp/ip/ip6tables is no longer available by default. Update your scripts to load br_netfilter if you need this.
1828:[   21.601791] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
1829:[   21.608352] IPv6: ADDRCONF(NETDEV_CHANGE): ens33: link becomes ready
1830:[   21.708661] e1000: ens33 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: None
1831-[   26.904983] tun: Universal TUN/TAP device driver, 1.6
1832-[   26.904986] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>

本来匹配到的前两行是18211822行,但通过使用-A(After)和-B(Before)参数,在结果中出现了18291820以及18231824行,这样有助于我们在某些情况下结合匹配结果的上下文分析问题。

基础正则表达式练习

这里使用《鸟哥的私房菜》提供的文本进行练习:

[icexmoon@xyz ~]$ cd /tmp
[icexmoon@xyz tmp]$ wget http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt
--2021-08-16 15:38:50--  http://linux.vbird.org/linux_basic/0330regularex/regular_express.txt
正在解析主机 linux.vbird.org (linux.vbird.org)... 140.116.44.180
正在连接 linux.vbird.org (linux.vbird.org)|140.116.44.180|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:650 [text/plain]
正在保存至: “regular_express.txt”

100%[===========================================================================================>] 650         --.-K/s 用时 0s

2021-08-16 15:38:56 (21.5 MB/s) - 已保存 “regular_express.txt” [650/650])
简单查找
[icexmoon@xyz tmp]$ grep -n the regular_express.txt
8:I can't finish the test.
12:the symbol '*' is represented as start.
15:You are the best is mean you are the no. 1.
16:The world <Happy> is the same with "glad".
18:google is the best tools for search keyword.
反选
[icexmoon@xyz tmp]$ grep -nv the regular_express.txt
1:"Open Source" is a good mechanism to develop programs.
2:apple is my favorite food.
3:Football game is not use feet only.
4:this dress doesn
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值