Shell脚本编程之正则表达式

141 阅读9分钟

一、概念 在 Shell 脚本中,正则表达式是一种强大且常用的文本处理工具,它可以用来匹配、搜索、替换和截取字符串。

    正则表达式是由一些字符去描述规则,在正则表达式中有两类字符

    (1)元字符(Meta Character):Shell 环境中具有特殊含义的字符,在命令行解释、文件名扩展、变量替换等方面起着关键作用。

    (2)普通字符:仅代表自身的字符。\元字符 ==> 普通字符

正则表达式也有不同的流派(如Egrep,java,C#)很多语言都用到了正则表达式,但是这些语言中用来描述字符串规则的"元字符"不是都一样的,因此称正则表达式有不同的流派。

正则表达式中匹配的三种量词:贪婪(Greedy)、勉强(Reluctant)、独占(Possessive)

二、元字符 元字符

含义

示例

说明

.

匹配一个除换行符以外的任意字符

a.b

匹配以a开头b结尾,中间有一个任意字符的单词

^

匹配行首

^ab

匹配以ab为行首的单词

$

匹配行尾

ab$

匹配以ab为行尾的单词

\

转义符

\

转换 < 原本的含义

< >

匹配一个指定的单词

\

精准匹配ab这个单词

|

逻辑或

ab|AB

匹配ab或者AB

\d

匹配任何数字,等同于[0-9]

grep -P '\d'

需要和grep等工具一起使用

\D

匹配一个非数字字符,等价于

grep -P '\D'

需要和grep等工具一起使用

\w

匹配任何字母,等同于[a-zA-Z0-9]

grep -P '\w'

需要和grep等工具一起使用

\W

匹配任何非单词字符,等同于[^a-zA-Z0-9]

grep -P '\W'

需要和grep等工具一起使用

\s

匹配任何空白字符(空格、制表符、换行符等)

grep -P '\s'

需要和grep等工具一起使用

\S

匹配任何非空白字符

grep -P '\S'

需要和grep等工具一起使用

\b

匹配单词边界

grep -P '\bhello\b'

单词的开头边界:\bword 匹配 "word"

单词的结尾边界:word\b 匹配 "word"

\B

匹配非单词边界

grep -P 'hello\B'

匹配单词内部的连接点:\Bcat\B 会匹配 "category" 中的 "cat"

确保匹配不发生在单词边界:\B-\B 会匹配 "a-b" 中的 -

    Shell程序实例

#/bin/bash

#使用 . 匹配任意字符 echo "small middle big ..." | grep "b.g"

#使用 ^ 匹配行首 echo -e "hello world\nByebye tony\nOK" | grep "^By"

#使用 匹配行尾echoe"Todayisagoodday\nJustsoso\n"grep"so 匹配行尾 echo -e "Today is a good day\nJust so so\n" | grep "so"

#使用 <> 匹配一个指定单词 echo -e "Pass CET6 and CET4" | grep "<CET6>"

#使用 \d 匹配任何数字 echo "abc 123 def" | grep -P "\d" Shell程序效果截图

三、字符范围匹配 字符

含义

示例

说明

[ ]

匹配一个指定范围的字符

a[xyz]b

匹配以a开头b结尾,中间有一个x或y或z的单词

[^ ]

匹配一个不在指定范围的字符

a[^xyz]b

匹配以a开头b结尾,中间有一个不是x或y或z的单词

Shell程序实例 (国内手机号码匹配)

    phone.txt

111102198910084421 13611112222 13133334444 15855556666 13177778888 13199990000 +8618611112222 990785199507319527 66666666666 phone.sh

#!/bin/bash

#Shell程序实例 (国内手机号码匹配) #基本正则表达式 grep -E '1[3-9][0-9]{9}' phone.txt #严格匹配(推荐) grep -P '\b1[3-9]\d{9}\b' phone.txt #带区号匹配 grep -P '(^|\s)(+86)?1[3-9]\d{9}(\s|$)' phone.txt Shell程序效果截图

四、字符重复匹配 1、贪婪匹配 非贪婪量词

含义(尽量重复的多)

示例

说明

使前面的字符重复0次或1次

a?

匹配a重复了0次或1次的单词

使前面的字符重复0次或多次

a*

匹配a重复了0次或多次的单词

使前面的字符重复1次或多次

a+

匹配a重复了1次或多次的单词

{n}

使前面的字符重复n次

a{6}

匹配a重复了6次的单词

{n,}

使前面的字符n次或以上

a{6,}

匹配a重复了6次或以上的单词

{n,m}

使前面的字符重复n次到m次

a{6,9}

匹配a重复了6次到9次的单词

    Shell程序实例(IPv4地址匹配)

#/bin/bash

ipstr="asdsdss192.a.65.4ddgdg192.168.258.990sgsfdg 123adsad 123 sa 676761234safd192.168.63.100fed"

#匹配 IPv4地址 #非严格匹配:快速提取 X.X.X.X 格式的字符串,可能数字超IPV4的范围 echo ipstr | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' #严格匹配:不仅匹配X.X.X.X 格式的字符串,还限制数字的范围 echo "ipstr" | grep -oE '((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' Shell程序效果截图

2、非贪婪匹配 非贪婪匹配就是在贪婪量词后面加个问号?

非贪婪量词

含义(尽量重复的少)

示例

说明

??

匹配 0 次或 1 次,但尽可能少

a??

尽量少地匹配a重复了0次或1次的单词

*?

匹配 0 次或多次,但尽可能少

a*?

尽量少地匹配a重复0次或多次的单词

+?

匹配 1 次或多次,但尽可能少

a+?

尽量少地匹配a重复了1次或多次的单词

{n}?

使前面的字符重复n次

a{6}?

尽量少地匹配a重复了6次的单词

{n,}?

使前面的字符n次或以上,但尽可能少

a{6,}?

尽量少地匹配a重复了6次或以上的单词

{n,m}?

使前面的字符重复n次到m次,但尽可能少

a{6,9}?

尽量少地匹配a重复6次到9次的单词

    Shell程序实例 (匹配 HTML 标签内容)

    Web 服务器日志 (access.log)

[2023-05-01 10:00:00] "GET /home HTTP/1.1" 200 "Mozilla/5.0" [2023-05-01 10:00:01] "POST /login HTTP/1.1" 302 "Chrome/114.0" [2023-05-01 10:00:02] "GET /profile?id=123&name=Alice HTTP/1.1" 200 "Safari/16.0" parse_log.sh

#!/bin/bash

echo "===== 日志分析结果 =====" echo "1. 时间戳:" grep -Po '[\K.*?(?=])' access.log

echo -e "\n2. HTTP 方法和路径:" grep -Po '"\K[A-Z]+ .*?(?= HTTP)' access.log

echo -e "\n3. 查询参数:" grep -Po 'GET /.?\K?.?(?= HTTP)' access.log

echo -e "\n4. User-Agent:" grep -Po '"\K[^"]*?(?="$)' access.log | tail -n +2 | sed -n 'p;n' Shell程序效果截图

五、常用文本处理命令 1、grep grep是Global search Regular Expression and Print out the line的简称,即全面搜索正则表达式并把行打印出来。

    grep(egrep):用来在文本文件里查一个特定的字符串。

    egrep用的是扩展的正则表达式。

grep [选项] [模式] [文件…]
grep options "正则表达式" filenames options: -n 显示行号 -E egrep用的是扩展的正则表达式 -i ignore 在字符串比较时忽略大小写 -c count 打印每个文件里匹配行的个数 --color=always 高亮显示
--color=never 不高亮显示 --color=auto 自动 -H 显示文件名 -h 不显示文件名 注意:默认情况下,grep命令打印出包含模式的所有行,一旦加上-c选项,就只显示包含模式行的数量

grep -n -E --color=always -H "([0-9]{1,3}.){3}[0-9]{1,3}" 1.txt 2、awk AWK 是一种强大的文本处理语言,特别适合处理结构化文本数据(如日志文件、CSV 文件等)。它以行为单位处理文本,并支持字段分割、模式匹配、计算和格式化输出等功能。

    awk:逐行读取文件,默认以 连续的空白字符(空格/制表符) 为分隔符将每行数据拆分为多个字段($1, $2...),然后可以对字段、整行($0)、行号(NR)等数据进行处理,支持计算、匹配、统计等操作。

awk options 'pattern {action}' file

pattern:正则表达式或条件,用于匹配行 action:匹配后执行的操作(如 print、计算等) file:输入文件(可省略,默认从 stdin 读取) options: -F 指定分隔符 -v 定义变量 -f 从脚本读取命令 -E 启用扩展正则 --posix 启用 POSIX 正则 基本匹配

awk '/正则表达式/' file #示例 awk '/error/' log.txt # 打印包含 "error" 的行 匹配特定字段

awk '2 ~ /正则表达式/' file #示例 awk '3 ~ /^[0-9]+$/' data.txt # 第 3 列是数字的行 反向匹配(不匹配)

awk '!/正则表达式/' file #示例 awk '!/warning/' log.txt # 打印不包含 "warning" 的行 3、sed sed全称为Stream Editor,是一个强大的流式文本编辑器,用于对文本进行过滤和转换。它特别适合用于批量编辑文件或处理文本流。

sed [选项] '命令' 文件

选项:控制 sed 的行为(如 -i 直接修改文件) 命令:指定对文本的操作(如替换 s/old/new/) 文件:输入文件(可省略,默认从 stdin 读取)

选项: -n 静默模式(仅打印处理的行) -i 直接修改文件(慎用!) -E/-r 启用扩展正则 -e 执行多条命令 --debug 调试模式(GNU sed 支持) 基本匹配

sed -n '/正则表达式/p' file #示例 sed -n '/error/p' log.txt # 打印包含 "error" 的行 替换(s///)

sed 's/正则表达式/替换内容/修饰符' file #示例 sed 's/foo/bar/g' file # 全局替换 "foo" 为 "bar" sed 's/[0-9]+/NUM/g' file # 替换所有数字为 "NUM"(+ 需转义) sed -E 's/[0-9]+/NUM/g' file # 同上,但用扩展正则(+ 无需转义) 删除(d)

sed '/正则表达式/d' file #示例 sed '/^#/d' file # 删除所有注释行(以 # 开头) sed '/^$/d' file # 删除所有空行 反向引用(\1, \2…)

sed 's/(正则表达式)/替换\1/' file #示例 sed 's/(foo) bar/\1 baz/' file # "foo bar" → "foo baz" sed -E 's/(foo) bar/\1 baz/' file # 扩展正则写法(括号无需转义) 4、cut cut 是一个简单但实用的文本处理工具,用于从文件或标准输入中提取文本的特定部分(如列或字符位置)。它特别适合处理结构化数据(如 CSV、TSV 或固定宽度的文本)。它 不支持正则表达式,但可以快速截取固定格式的字段。

cut放进到本文中一起讲解,主要是给使用shell编程设计的大伙们,提供一个参考比对借鉴的工具。

cut [选项] [文件]

选项 :指定如何截取文本(如按字符、字段等)。 文件 :输入文件(可省略,默认从 stdin 读取)

选项 : -d 指定 分隔符(默认 TAB) -f 选择 字段(列) -c 选择字符位置 -s 仅显示包含分隔符的行 --complement 反选(排除指定列) 按字段(列)提取

cut -d':' -f1,3 /etc/passwd #示例输出 root:0 daemon:1 bin:2 ... 按字符位置提取

echo "abcdefgh" | cut -c2-5 #示例输出 (提取第 2~5 个字符) bcde 排除某些列

#(提取 data.csv 中 除了第 2 列 的所有列) cut -d',' -f2 --complement data.csv 处理 CSV 文件

#(先过滤含 "ERROR" 的行,再提取第 3 列) cut -d',' -f1,3 employees.csv 提取固定宽度的数据

#(提取第 110 和第 2030 个字符) cut -c1-10,20-30 data.txt 结合 grep 过滤后提取

#(先过滤含 "ERROR" 的行,再提取第 3 列) grep "ERROR" log.txt | cut -d' ' -f3 5、wc wc(Word Count)是一个用于 统计文件或文本的行数、单词数、字符数 的简单工具,常用于日志分析、代码统计等场景。

wc [选项] [文件...]

选项:控制统计的内容(如仅显示行数)。 文件:输入文件(可省略,默认从 stdin 读取)。 选项: -l 仅统计 行数(Line) -w 仅统计 单词数(Word) -c 仅统计 字节数(Byte) -m 仅统计 字符数(适用于 Unicode) -L 显示 最长行的长度 无选项 显示 行数、单词数、字节数 基础使用案例

#基本统计 wc file.txt #输出结果 12 45 230 file.txt #12:行数;45:单词数(以空格分隔);230:字节数

#仅统计行数 wc -l file.txt #输出结果 12 file.txt

#统计多个文件 wc *.txt #输出结果 12 45 230 file1.txt 20 80 400 file2.txt 32 125 630 total

#结合 grep 统计匹配行数 grep "ERROR" log.txt | wc -l #(统计 log.txt 中包含 "ERROR" 的行数)

#统计代码行数 find . -name "*.py" -exec wc -l {} ; #(统计当前目录下所有 .py 文件的行数) 6、sort sort 是 Linux 中用于 对文本行进行排序 的强大工具,支持按字母、数字、月份等多种规则排序,并能去重、合并文件等。

sort [选项] [文件]

选项:控制排序规则(如降序、按数字排序等) 文件:输入文件(可省略,默认从 stdin 读取)

选项: -r 降序排序(默认升序) -n 按数字排序(默认按字符串) -k 指定排序的列 -u 去重(仅保留唯一行) -f 忽略大小写 -t 指定列分隔符 -o 结果输出到文件 -m 合并已排序的文件 -c 检查文件是否已排序 ... 基础使用案例

#1、基本排序(按字母升序) sort fruit.txt #输出结果 banana apple orange

#2、按数字排序 sort -n numbers.txt #numbers.txt文件输入: 10 2 45 #输出 2 10 45

#3、按指定列排序 sort -t',' -k2 data.csv #输入(data.csv): Alice,25 Bob,30 Eve,20 #输出: Eve,20 Alice,25 Bob,30

#4、降序排序 + 去重 sort -r -u names.txt #输入: Alice Bob Alice #输出: Bob Alice

#5、检查文件是否已排序 #若已排序,无输出;未排序则报错。 sort -c file.txt

#6、合并多个已排序文件 sort -m sorted1.txt sorted2.txt linuxShellssh运维服务器开发语言bash 文章来源:ximaonetwork.cn