欢迎光临
我们一直在努力

Shell编程之正则表达与文本处理器

  • Linux 文本处理三剑客:正则表达式、sed 与 awk 

在 Linux 系统的日常运维和开发工作中,文本处理是一项核心技能。无论是分析日志、配置文件,还是自动化脚本编写,我们都离不开强大的文本处理工具。

本文将带你深入理解正则表达式,并掌握sed和awk这两个被誉为 “文本处理三剑客” 的工具,让你在处理文本时游刃有余。


一、正则表达式:文本匹配的魔法

1. 什么是正则表达式?

正则表达式(Regular Expression,简称 regex),是一种用于描述、匹配一系列符合某个句法规则的字符串的方法。你可以把它想象成一个 “模板”,用来在海量的文本中快速找到你需要的内容。

对于普通计算机用户来说,可能很少直接接触到它,但对于系统管理员和开发者而言,正则表达式是必备的 “瑞士军刀”。它能帮你从纷繁复杂的日志中快速定位 “用户登录失败”、“服务启动错误” 等关键信息,也能让邮件服务器高效地过滤垃圾邮件。

2. 基础正则表达式:从简单开始

基础正则表达式是构建更复杂匹配规则的基石,我们先来认识几个最常用的元字符:

(1)锚定字符:定位行首与行尾

有时候我们不关心字符串在句子中间,而是想精确找到 “以什么开头” 或 “以什么结尾” 的行,这时候就需要用到锚定字符。

  • ^:行首锚定符,用来匹配行的开始位置。

例如,要查找test.txt文件中所有以the开头的行,可以使用:

bash

grep -n '^the' test.txt

这条命令会输出所有行首是the的行,并显示行号。

  • $:行尾锚定符,用来匹配行的结束位置。例如,要查找所有以小数点.结尾的行,因为.在正则中是特殊字符,需要用反斜杠\\转义:

 bash

grep -n '\\.$' test.txt

(2)任意字符与重复:灵活匹配

文本中充满了不确定性,我们需要元字符来处理这种 “模糊” 的情况。

  • .:点号,代表任意一个字符。例如,要查找所有以w开头,d结尾,中间夹着任意一个字符的单词(如wod、wdd、w2d),可以用:

    bash

    grep -n 'w.d' test.txt

    它会匹配到像wood(这里oo被视为两个.的匹配)这样的字符串。

  • *:星号,代表前面的一个字符可以重复零次或多次。结合.使用,.*就成了 “匹配任意长度的任意字符” 的经典组合。例如,要查找所有以w开头,d结尾,中间可以有任意多个字符(包括没有字符)的行:

    bash

    grep -n 'w.*d' test.txt

    这条命令会匹配wd、wood、woooood等所有符合条件的字符串。

(3)字符集合:精准筛选

当你需要匹配 “某一类” 字符,而不是一个具体的字符时,字符集合[]就派上用场了。

[abc]:匹配a、b或c中的任意一个字符。例如,要同时查找shirt和short这两个单词,它们都包含sh和rt,中间的字母是i或o:

bash

grep -n 'sh[io]rt' test.txt

这条命令会一次性匹配到这两个单词所在的行。

  • [a-z]:匹配所有小写英文字母。要查找所有以小写字母开头的行:

    bash

    grep -n '^[a-z]' test.txt

  • [^a-z]:注意,在[]内部的^是 “取反” 的意思,代表 “不匹配”。要查找所有不以小写字母开头的行:

    bash

    grep -n '^[^a-z]' test.txt

(4)限定连续字符范围:精确控制次数

*虽然好用,但它太 “自由” 了。如果你想精确控制一个字符出现的次数,比如 “恰好出现 2 次”、“至少出现 2 次”,就需要用到{}。

  • \\{n\\}:前面的字符恰好重复n次。例如,查找恰好包含两个连续o的字符串:

    bash

    grep -n 'o\\{2\\}' test.txt

  • \\{n,m\\}:前面的字符至少重复n次,最多重复m次。例如,查找以w开头,d结尾,中间包含 2 到 5 个o的字符串(如wood、woooood):

    bash

    grep -n 'wo\\{2,5\\}d' test.txt

  • \\{n,\\}:前面的字符至少重复n次。例如,查找以w开头,d结尾,中间包含 2 个或更多o的字符串:

    bash

    grep -n 'wo\\{2,\\}d' test.txt

⚠️ 注意:在基础正则表达式中,{和}是特殊字符,需要用反斜杠\\进行转义,写成\\{ \\}。

3. 扩展正则表达式:简化你的指令

基础正则表达式虽然强大,但在处理一些复杂逻辑时,命令会变得冗长。这时,我们可以使用扩展正则表达式(Extended Regular Expression, ERE),它在基础正则的基础上增加了几个元字符,让指令更简洁。要使用扩展正则,需要用egrep命令或者grep -E选项。

  • +:匹配前面的字符一次或多次(等价于\\{1,\\})。
  • ?:匹配前面的字符零次或一次(等价于\\{0,1\\})。
  • |:表示 “或” 的逻辑,匹配|两边任意一个表达式。

例如,使用基础正则查找fish或fosh需要写成fis|osh,而使用扩展正则则更直观:

bash

egrep -n 'fi|os' test.txt

这条命令会同时匹配到包含fi或os的行。


二、sed:流编辑器,文本处理的自动化大师

如果说正则表达式是 “查找” 的利器,那么sed(Stream Editor)就是 “编辑” 的神器。它是一个非交互式的文本编辑器,可以对文本文件进行自动的删除、替换、添加、插入等操作,是编写 Shell 脚本自动化处理文本的首选工具。

1. sed 的工作原理

sed的工作流程非常清晰,主要分为三个步骤:

  • 读取(Read):从输入流(文件、管道、标准输入)中逐行读取内容,并存储到一个叫做 “模式空间”(pattern space)的缓冲区中。
  • 执行(Execute):在模式空间中,按照你指定的sed命令对文本进行编辑。默认情况下,所有命令会在所有行上依次执行,除非你指定了行号或正则表达式作为过滤条件。
  • 显示(Display):将编辑后的内容发送到标准输出(屏幕)。完成后,模式空间会被清空,然后读取下一行,重复整个过程。
  • ⚠️ 重要提示:默认情况下,sed不会修改原始文件,所有的修改都只发生在内存的模式空间中。如果你想直接修改源文件,需要使用-i选项。

    2. 核心操作:p(打印)、d(删除)、s(替换)

    sed的命令非常丰富,但最核心、最常用的就是以下三个操作:

    (1)打印(p):输出你关心的行

    p命令用于打印模式空间中的内容。通常和-n选项一起使用,-n会抑制sed默认的 “自动打印” 行为,只打印我们明确指定的行。

    • 打印第 3 行:

      bash

      sed -n '3p' test.txt

    • 打印第 3 到第 5 行:

      bash

      sed -n '3,5p' test.txt

    • 打印所有奇数行(n表示读入下一行):

      bash

      sed -n 'p;n' test.txt

    • 打印包含特定字符串(如PI)的行:

      bash

      sed -n '/PI/p' test.txt

    (2)删除(d):清理无用信息

    d命令用于删除模式空间中的行。

    • 删除第 3 行:

      bash

      sed '3d' test.txt

    • 删除第 3 到第 5 行:

      bash

      sed '3,5d' test.txt

    • 删除所有空行:

      bash

      sed '/^$/d' test.txt

    • 删除所有以小写字母开头的行:

      bash

      sed '/^[a-z]/d' test.txt

    (3)替换(s):最强大的文本改造

    s(substitute)命令是sed中最强大的功能,用于文本替换。它的基本格式是:s/要查找的字符串/替换成的字符串/修饰符。

    • 将每行中第一个出现的the替换为THE:

      bash

      sed 's/the/THE/' test.txt

    • 将文件中所有的the替换为THE(使用g修饰符,表示 global):

      bash

      sed 's/the/THE/g' test.txt

    • 在每一行的行首插入一个#号(常用于注释):

      bash

      sed 's/^/#/' test.txt

    • 将文件中所有的字母o删除(替换为空字符串):

      bash

      sed 's/o//g' test.txt

    3. 进阶操作:脚本化与直接编辑

    当需要执行多个sed操作时,把它们写在一行会非常混乱。sed允许你通过-f选项,从一个脚本文件中读取并执行命令。

    例如,创建一个名为opt.list的脚本文件,内容如下:

    plaintext

    1,5H
    1,5d
    17G

    然后执行:

    bash

    sed -f opt.list test.txt

    这个脚本会先将 1-5 行的内容复制到剪贴板(H),然后删除这 5 行(d),最后将剪贴板的内容追加到第 17 行之后(G),实现了文本块的移动。

    对于需要频繁修改的配置文件,我们甚至可以直接在sed命令中使用-i选项,实现对源文件的 “原地” 编辑,这在自动化脚本中非常方便。


    三、awk:字段分析与报告生成器

    如果说sed擅长处理 “整行” 的文本,那么awk则更擅长处理 “结构化” 的文本,比如 CSV 文件、系统日志、/etc/passwd这样的配置文件。它把每一行看作一个 “记录”,把行中的每一列看作一个 “字段”,让你可以像操作数据库一样轻松提取和分析数据。

    1. awk 的核心概念:记录与字段

    • 记录(Record):awk默认将每一行视为一个独立的 “记录”,用内置变量NR(Number of Records)来记录当前处理的是第几行。
    • 字段(Field):awk会自动将每一行按照分隔符(默认是空格或制表符)切分成若干个 “字段”。第一个字段是$1,第二个是$2,以此类推,整个行是$0。内置变量NF(Number of Fields)表示当前行有多少个字段。

    以 Linux 系统的/etc/passwd文件为例,它的每一行格式是用户名:密码占位符:UID:GID:注释:家目录:登录Shell,字段之间用冒号:分隔。我们可以用-F选项指定分隔符:

    bash

    awk -F ':' '{print $1, $3, $4}' /etc/passwd

    这条命令会打印出所有用户的用户名、UID 和 GID,非常直观。

    2. awk 的强大之处:编程能力

    awk不仅仅是一个提取工具,它更是一门完整的编程语言,支持变量、数组、条件判断、循环和函数。

    (1)内置变量

    awk提供了很多方便的内置变量,让你无需重复造轮子:

    • FS:字段分隔符(Field Separator),默认是空格。
    • NF:当前记录的字段个数。
    • NR:当前处理的记录号(行号)。
    • $0:当前记录的整行内容。
    • FILENAME:当前处理的文件名。
    (2)模式与动作

    awk命令的基本结构是'模式 { 动作 }'。

    • 模式(Pattern):可以是正则表达式、条件表达式,或者BEGIN/END这样的特殊关键字。只有当模式匹配时,后面的动作才会执行。
    • 动作(Action):用大括号{}包裹的一系列命令,比如print、变量赋值、循环等。

    例如,统计/etc/passwd中以/bin/bash作为登录 Shell 的用户数量:

    bash

    awk 'BEGIN {x=0}; /\\/bin\\/bash$/ {x++}; END {print x}' /etc/passwd

    • BEGIN {x=0}:在处理任何文件之前,先初始化计数器x为 0。
    • /\\/bin\\/bash$/ {x++}:对于每一行,如果行尾是/bin/bash,就将计数器x加 1。
    • END {print x}:在所有文件处理完毕后,打印出计数器x的值,也就是符合条件的用户总数。
    (3)调用外部命令

    awk甚至可以通过system()函数或者管道|来调用外部的 Shell 命令,实现更复杂的功能。

    例如,在awk中调用wc -l命令来统计用户数:

    bash

    awk -F: '/bash$/{print | "wc -l"}' /etc/passwd

    或者调用hostname命令获取主机名:

    bash

    awk 'BEGIN {"hostname" | getline; print $0}'


    四、总结与实战建议

    正则表达式、sed和awk是 Linux 文本处理的三把利刃,它们各有所长:

    • 正则表达式是基础,是所有文本匹配的灵魂。
    • sed 适合对文本进行快速的行级编辑和转换。
    • awk 则在分析和提取结构化数据时表现出色。

    在实际工作中,它们经常被组合使用,通过管道|连接起来,形成强大的文本处理流水线。

    赞(0)
    未经允许不得转载:171主机测评 » Shell编程之正则表达与文本处理器
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址