正則表達式基礎與實踐
一、正則表達式概述
1. 定義
正則表達式(Regular Expression,簡稱 RE)是用于描述字符排列和匹配模式的語法規則,核心作用是對字符串進行分割、匹配、查找、替換操作。它本質是 “模式模板”,Linux 工具(如 grep、egrep、awk)可通過該模板過濾文本數據流,最終輸出 “匹配的數據” 或 “濾掉的數據”。
2. 應用場景
- 判斷字符串是否符合特定格式(如手機號、郵箱、日期);
- 從大量文本中提取目標內容(如日志中的 IP 地址、錯誤信息);
- 批量替換文本中的指定字符或格式。
3. 組成結構
正則表達式由 普通字符 和 元字符 組成:
- 普通字符:大小寫字母(A-Z、a-z)、數字(0-9)、標點符號(!、@、# 等)及其他常規符號,僅匹配自身;
- 元字符:具有特殊意義的專用字符,用于規定前導字符的出現模式(如匹配開頭、結尾、重復次數等)。
二、基礎正則表達式(BRE)
基礎正則表達式是正則的核心語法,適用于 grep、sed 等工具,以下是常用元字符及示例:
元字符 | 功能說明 | 示例 | 示例說明 |
\ | 轉義字符,取消后續特殊符號的含義 | \!、\$、\n | 匹配 !、$、換行符 \n |
^ | 匹配字符串的開始位置 | ^a、^the、^# | 匹配以 a、the、# 開頭的行 |
$ | 匹配字符串的結束位置 | word$、^$ | 匹配以 word 結尾的行;^$ 匹配空行 |
. | 匹配除換行符 \n 以外的任意一個字符 | lo.k、l..k | 匹配 lok(o 和 k 間 1 個任意字符)、lbck(l 和 k 間 2 個任意字符) |
* | 匹配前面一個字符出現0 次或多次(可重復任意次,包括不出現) | loo*k、lo*k | loo*k 匹配 lk(0 個 o)、lok(1 個 o)、look(2 個 o)等;lo*k 同理 |
[list] | 匹配 list 列表中的任意一個字符(列表可是字符集、范圍) | go[ola]d、[a-z]、[0-9] | go[ola]d 匹配 gold、goal、god;[0-9] 匹配任意 1 位數字 |
[^list] | 匹配非 list 列表中的任意一個字符(取反) | [^0-9]、[^a-z] | [^0-9] 匹配非數字字符;[^a-z] 匹配非小寫字母 |
\{n\} | 匹配前面一個字符恰好 n 次(grep 需加 \,egrep/awk 無需加) | lo\{2\}k、[0-9]\{2\} | lo\{2\}k 匹配 look(o 出現 2 次);[0-9]\{2\} 匹配任意 2 位數字 |
\{n,\} | 匹配前面一個字符不少于 n 次(≥n 次) | lo\{2,\}k、[0-9]\{2,\} | lo\{2,\}k 匹配 look(2 次 o)、loook(3 次 o)等;[0-9]\{2,\} 匹配 2 位及以上數字 |
\{n,m\} | 匹配前面一個字符n 到 m 次(≥n 且 ≤m 次) | lo\{2,3\}k、[0-9]\{2,3\} | lo\{2,3\}k 匹配 look(2 次 o)、loook(3 次 o);[0-9]\{2,3\} 匹配 2-3 位數字 |
基礎正則實踐(基于 a.txt 文本)
1. 準備測試文本 a.txt
先創建文本文件,內容如下:
lkloklookloooklooooookloooooaaaklooooooookabbbbcdabbbbcd666ooooloooookoooooolkaoblck
2. 實踐案例(grep 命令)
命令 | 匹配邏輯 | 輸出結果(a.txt 中匹配的行) |
grep "loo*k" a.txt | 匹配 l 后接任意次 o(0 次及以上),再接 k | lok、look、loook、looooook、looooooook、ooooloooook |
grep "lo.k" a.txt | 匹配 l 后接 o、1 個任意字符,再接 k | look(o 和 k 間是 o,符合 “1 個任意字符”) |
grep "lo.*k" a.txt | 匹配 l 后接 o、任意個任意字符(0 次及以上),再接 k | lok、look、loook、looooook、loooooaaak、looooooook、ooooloooook(o 和 k 間可含字母如 aaa) |
grep "lo\{2\}k" a.txt | 匹配 l 后接 2 次 o,再接 k | look |
grep "lo\{2,\}k" a.txt | 匹配 l 后接≥2 次 o,再接 k | look、loook、looooook、looooooook、ooooloooook |
grep "lo\{2,3\}k" a.txt | 匹配 l 后接 2-3 次 o,再接 k | look(2 次 o)、loook(3 次 o) |
grep "^a" a.txt | 匹配以 a 開頭的行 | abbbbcd、abbbbcd666、aoblck |
grep "6$" a.txt | 匹配以 6 結尾的行 | abbbbcd666 |
三、擴展正則表達式(ERE)
擴展正則表達式在基礎正則上新增了元字符,功能更靈活,適用于 egrep(grep -E)、awk 等工具(無需對 {}、+ 等元字符轉義,grep 需加 \ 轉義)。
元字符 | 功能說明 | 示例 | 示例說明 |
+ | 匹配前面一個字符出現1 次及以上(至少出現 1 次,區別于 * 的 “0 次及以上”) | lo+k | 匹配 lok(1 次 o)、look(2 次 o)、loook(3 次 o)等,不匹配 lk(0 次 o) |
? | 匹配前面一個字符出現0 次或 1 次(最多出現 1 次) | lo?k | 匹配 lk(0 次 o)、lok(1 次 o),不匹配 look(2 次 o) |
() | 將括號中的字符串作為一個整體(分組),用于批量匹配或重復 | l(oo)+k | 把 oo 視為整體,匹配 look(1 次 oo)、looook(2 次 oo)等 |
` | ` | 邏輯 “或”,匹配 ` | ` 兩側任意一個表達式 |
{n} | 同基礎正則 \{n\},匹配前面字符恰好 n 次(無需轉義) | lo{3}k | 匹配 loook(o 出現 3 次) |
{n,} | 同基礎正則 \{n,\},匹配前面字符≥n 次(無需轉義) | lo{3,}k | 匹配 loook(3 次 o)、looooook(5 次 o)等 |
{n,m} | 同基礎正則 \{n,m\},匹配前面字符 n-m 次(無需轉義) | lo{3,5}k | 匹配 loook(3 次 o)、looooook(5 次 o),不匹配 looooooook(6 次 o) |
擴展正則實踐(基于 a.txt 文本)
使用 egrep 命令(支持擴展正則,無需轉義),實踐案例如下:
命令 | 匹配邏輯 | 輸出結果(a.txt 中匹配的行) |
egrep "lo+k" a.txt | 匹配 l 后接≥1 次 o,再接 k | lok、look、loook、looooook、looooooook、ooooloooook |
egrep "lo?k" a.txt | 匹配 l 后接 0-1 次 o,再接 k | lk(0 次 o)、lok(1 次 o)、oooooolk(ooooo 后接 o?,即 0-1 次 o,最終匹配 oooooolk) |
egrep "l(oo)+k" a.txt | 匹配 l 后接≥1 次 oo 組,再接 k | look(1 次 oo)、looooook(2 次 oo)、looooooook(3 次 oo)、ooooloooook(含 oo 組) |
`egrep "(oo | ab)" a.txt` | 匹配含 oo 或 ab 的行 |
egrep "lo{3}k" a.txt | 匹配 l 后接 3 次 o,再接 k | loook |
egrep "lo{3,}k" a.txt | 匹配 l 后接≥3 次 o,再接 k | loook、looooook、looooooook、ooooloooook |
egrep "lo{3,5}k" a.txt | 匹配 l 后接 3-5 次 o,再接 k | loook(3 次 o)、ooooloooook(loooo 即 4 次 o,符合 3-5 次范圍) |
四、補充實踐(基于 b.txt 文本)
1. 準備測試文本 b.txt
創建文本文件,內容如下:
loklo12klo1kloAkloBklookloaklodkabcd1234
2. 案例(基礎 / 擴展正則結合)
命令 | 正則類型 | 匹配邏輯 | 輸出結果(b.txt 中匹配的行) |
grep "[a-zA-Z0-9]k" b.txt | 基礎 | 匹配 “字母 / 數字 + k” 的組合 | lo1k、loAk、loBk、look、loak、lodk |
grep "lo[ABo]k" b.txt | 基礎 | 匹配 lo 后接 A/B/o,再接 k | loAk、loBk、look |
grep "lo[^a-zA-Z]k" b.txt | 基礎 | 匹配 lo 后接 “非字母”,再接 k | lo1k(lo 后是數字 1,非字母) |
grep "[^a-zA-Z]" b.txt | 基礎 | 匹配含 “非字母” 的行(即含數字、符號等) | lo12k、lo1k、1234 |
五、工具使用說明
工具 | 支持的正則類型 | 特殊說明(元字符轉義) |
grep | 基礎正則(BRE) | 使用 {n}、{n,}、{n,m} 需加轉義 \(如 \{2\});擴展正則需加 -E 參數(grep -E 等價于 egrep) |
egrep | 擴展正則(ERE) | 無需轉義 {}、+、?、()、` |
awk | 擴展正則(ERE) | 無需轉義,支持所有擴展正則元字符 |
sed | 基礎正則(BRE) | 使用擴展正則需加 -r 參數 |
Linux 文本處理三劍客(grep、sed、awk)
一、grep:文本過濾工具
grep 是 Linux 中最基礎的文本過濾工具,核心功能是按 “字符串” 或 “正則表達式” 篩選文本行,僅輸出匹配的內容,常用于日志分析、配置文件檢索等場景。
1. 核心語法
grep [選項] "匹配規則" 目標文件
2. 常用選項與功能
選項 | 功能說明 | 示例 |
無選項 | 直接匹配包含 “字符串” 的行,輸出整行內容 | grep "blp5" /tmp/services(輸出含 “blp5” 的行) |
-v | 反向匹配:輸出不包含“字符串” 的行 | grep -v "udp" /tmp/services(輸出不含 “udp” 的行) |
-i | 忽略大小寫:匹配時不區分字母大小寫 | grep -i "BLP5" /tmp/services(同時匹配 “blp5”“BLP5” 等) |
-o | 僅顯示匹配部分:不輸出整行,只打印匹配的字符串 | grep -o "48[0-9]\+" /tmp/services(僅輸出以 “48” 開頭的數字) |
-n | 顯示行號:輸出匹配行的行號及內容 | grep -n "tcp" /tmp/services(輸出含 “tcp” 的行號 + 內容) |
-E | 支持擴展正則表達式(等價于 egrep) | grep -E "lo{2,3}k" a.txt(匹配 “look”“loook”) |
3. 常用匹配規則(結合正則)
匹配規則 | 功能 | 示例 |
^字符串 | 匹配以 “字符串” 開頭的行 | grep "^blp5" /tmp/services(輸出以 “blp5” 開頭的行) |
字符串$ | 匹配以 “字符串” 結尾的行 | grep "6$" a.txt(輸出以 “6” 結尾的行) |
^$ | 匹配空行 | grep -v "^$" /etc/httpd/conf/httpd.conf(過濾配置文件空行) |
[字符集] | 匹配字符集中的任意一個字符 | grep "lo[ABo]k" b.txt(匹配 “loAk”“loBk”“look”) |
[^字符集] | 匹配非字符集中的任意一個字符 | grep "lo[^a-z]k" b.txt(匹配 “lo1k”,不匹配 “loak”) |
4. 典型場景示例
- 過濾 Apache 配置文件注釋行和空行:
grep -v "^#" /etc/httpd/conf/httpd.conf | grep -v "^$"
- 從日志中提取 IP 地址(假設日志含 “192.168.x.x” 格式 IP):
grep -o "192\.168\.[0-9]\+\.[0-9]\+" /var/log/access.log
二、sed:流編輯器(文本修改工具)
sed(Stream Editor)是 “流編輯器”,核心功能是按規則逐行處理文本(修改、刪除、添加、替換),處理時不直接修改原文件(需 -i 選項),常用于批量修改配置、文本格式化等場景。
sed 的核心邏輯:將文本行逐行讀入 “模式空間”(臨時緩沖區),按命令處理后輸出,再處理下一行,直到文件結束。
1. 核心語法
sed [選項] "地址范圍 命令" 目標文件
創建文本文件,內容如下:
cat /tmp/services
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/t//cp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
2. 常用選項
選項 | 功能說明 | 示例 |
-n | 不打印模式空間:僅輸出被命令處理后的行(需配合 p 命令) | sed -n "1,3p" /tmp/services(僅輸出 1-3 行) |
-i | 直接修改原文件:無需重定向,直接覆蓋原文件內容(慎用!) | sed -i "s/blp5/test/g" /tmp/services(將原文件中 “blp5” 替換為 “test”) |
-e | 執行多個命令:一次處理中執行多個 sed 命令 | sed -e "1,4d" -e "s/blp5/test/" /tmp/services(先刪 1-4 行,再替換字符串) |
-f | 從文件讀取命令:將 sed 命令寫入文件,通過 -f 調用 | sed -f sed_commands.txt /tmp/services(sed_commands.txt 中存 sed 命令) |
-r | 支持擴展正則表達式:無需對 {} + 等元字符轉義 | sed -r "s/(lo{2})k/\1_test/" a.txt(匹配 “look” 并替換為 “loo_test”) |
3. 關鍵概念:地址范圍(指定處理哪些行)
sed 通過 “地址范圍” 限定命令作用的行,常見格式如下:
地址范圍格式 | 功能 | 示例 |
數字 | 僅處理第 N 行 | sed "5d" /tmp/services(刪除第 5 行) |
數字1,數字2 | 處理第 N1 行到第 N2 行 | sed "1,3p" /tmp/services(打印 1-3 行) |
數字,+$N | 從第 N 行開始,向后 N 行 | sed "/blp5/,+1p" /tmp/services(打印 “blp5” 行及后 1 行) |
數字~步長 | 從第 N 行開始,每 “步長” 行處理一次 | sed "1~2d" /tmp/services(刪除奇數行,步長 = 2) |
/正則/ | 處理匹配 “正則” 的行 | sed "/^blp5/d" /tmp/services(刪除以 “blp5” 開頭的行) |
/正則1/,/正則2/ | 處理 “正則 1” 匹配行到 “正則 2” 匹配行 | sed "/^blp5/,/^com/p" /tmp/services(打印 “blp5” 到 “com” 開頭的行) |
$ | 處理最后一行 | sed "$d" /tmp/services(刪除最后一行) |
4. 常用 sed 命令(處理文本的核心操作)
命令 | 功能 | 示例 |
p | 打印:輸出模式空間中的行(需配合 -n) | sed -n "1~2p" /tmp/services(打印奇數行) |
d | 刪除:刪除模式空間中的行,不輸出 | sed "/udp/d" /tmp/services(刪除含 “udp” 的行) |
s/舊值/新值/[選項] | 替換:將 “舊值” 替換為 “新值”,默認僅替換每行第一個匹配 | - s/blp5/test/:替換每行第一個 “blp5” 為 “test” - s/blp5/test/g:g(全局替換),替換每行所有 “blp5” - s/48049/&.123/:& 引用匹配內容,將 “48049” 改為 “48049.123” |
a \文本 | 追加:在匹配行下方添加 “文本” | sed "/blp5/a \new_line" /tmp/services(在 “blp5” 行下加 “new_line”) |
i \文本 | 插入:在匹配行上方添加 “文本” | sed "/blp5/i \new_line" /tmp/services(在 “blp5” 行上加 “new_line”) |
c \文本 | 替換行:將匹配行整體替換為 “文本” | sed "/blp5/c \replace_line" /tmp/services(將 “blp5” 行替換為 “replace_line”) |
r 文件名 | 讀取文件:將 “文件名” 的內容追加到匹配行下方 | sed "/blp5/r a.txt" /tmp/services(在 “blp5” 行下追加 a.txt 內容) |
w 文件名 | 寫入文件:將匹配行寫入 “文件名”(不影響屏幕輸出) | sed "/blp5/w b.txt" /tmp/services(將 “blp5” 行保存到 b.txt) |
5. 典型場景示例
- 批量替換配置文件中的字符串(修改原文件):
sed -i "s/Listen 80/Listen 8080/g" /etc/httpd/conf/httpd.conf
- 刪除日志文件中第 10-20 行的注釋(假設注釋以 “#” 開頭):
sed -i "10,20s/^#//" /var/log/app.log
- 將文本中 “端口 / 協議” 格式(如 48003/udp)改為 “協議 / 端口”(如 udp/48003):
sed -r "s/(.*)([0-9]+)\/(tcp|udp)(.*)/\1\3\/\2\4/" /tmp/services
三、awk:文本處理編程語言
awk 是功能最強大的文本處理工具,兼具 “編程語言” 特性,支持字段分割、變量運算、條件判斷、循環等,核心優勢是 “按字段處理文本”(如表格數據、日志的字段提取),常用于數據統計、報表生成等場景。
awk 的核心邏輯:將文本逐行視為 “記錄”,每行按 “分隔符” 拆分為多個 “字段”(默認分隔符為空格 / 制表符),通過 $1 $2... 引用字段($0 表示整行)。
1. 核心語法
awk [選項] '模式 { 動作 }' 目標文件
- 模式:指定處理哪些行(如 BEGIN END、正則、行號范圍);
- 動作:對匹配的行執行的操作(如打印字段、運算、判斷)。
2. 常用選項
選項 | 功能說明 | 示例 |
-F 分隔符 | 指定字段分隔符(默認是空格 / 制表符) | awk -F ":" '{print $1,$3}' /etc/passwd(以 “:” 為分隔符,打印第 1、3 字段) |
-v 變量=值 | 定義 awk 變量(在處理文本前賦值) | awk -v num=5 '$3 > num {print $0}' /etc/passwd(打印第 3 字段大于 5 的行) |
-f 文件名 | 從文件讀取 awk 腳本(將 “模式 + 動作” 寫入文件) | awk -f script.awk /tmp/services(script.awk 中存 awk 邏輯) |
--profile=[文件] | 將 awk 命令格式化輸出到文件(便于調試) | awk --profile=prof.txt 'BEGIN{print "test"}'(將腳本寫入 prof.txt) |
3. 核心模式(控制處理范圍)
模式 | 功能 | 示例 |
BEGIN { 動作 } | 處理文本前執行(僅執行一次),常用于初始化變量、打印表頭 | awk 'BEGIN{print "Service\tPort"; print "==="}' /tmp/services(先打印表頭) |
END { 動作 } | 處理文本后執行(僅執行一次),常用于統計結果、打印表尾 | awk '{count++} END{print "總行數:"count}' /tmp/services(統計文件總行數) |
/正則/ | 處理匹配 “正則” 的行 | awk '/tcp/{print $1,$2}' /tmp/services(打印含 “tcp” 的行的第 1、2 字段) |
行號范圍 | 處理指定行號的行 | awk '1,3{print $0}' /tmp/services(打印 1-3 行) |
條件判斷 | 處理滿足條件的行 | awk '$2 ~ /48129/{print $0}' /tmp/services(第 2 字段含 “48129” 的行) |
4. 常用內置變量(無需定義直接使用)
內置變量 | 功能 | 示例 |
$0 | 表示當前行的完整內容 | awk '{print $0}' /tmp/services(打印整行) |
$n | 表示當前行的第 n 個字段(n 為數字) | awk -F ":" '{print $1}' /etc/passwd(打印用戶名,第 1 字段) |
NF | 表示當前行的 “字段總數” | awk '{print "當前行字段數:"NF}' /tmp/services(輸出每行的字段數) |
NR | 表示當前行的 “行號”(整個文件的行號) | awk 'NR>5{print NR,$0}' /tmp/services(打印行號大于 5 的行) |
FS | 字段分隔符(等價于 -F 選項,默認是空格) | awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd(以 “:” 為分隔符) |
OFS | 輸出字段分隔符(默認是空格) | `awk 'BEGIN{FS=":";OFS=" |
5. 典型場景示例
- 統計 /etc/passwd 中 UID 大于 1000 的用戶數:
awk -F ":" '$3 > 1000 {count++} END{print "普通用戶數:"count}' /etc/passwd
- 從 Apache 訪問日志(假設格式為 “IP 時間 請求路徑”)中提取訪問最多的前 5 個 IP:
awk '{print $1}' /var/log/access.log | sort | uniq -c | sort -nr | head -5
- 格式化輸出 /tmp/services 內容(添加表頭、對齊字段):
awk 'BEGIN{print "Service\t\tPort/Protocol\tDescription";print "----------------------------------------"} {printf "%-15s %-15s %s\n", $1, $2, $3}' /tmp/services
結果
Service Port Description
===
nimgtw 48003/udp # Nimbus Gateway
3gpp-cbsp 48049/tcp # 3GPP Cell Broadcast Service Protocol
isnetserv 48128/tcp # Image Systems Network Services
isnetserv 48128/udp # Image Systems Network Services
blp5 48129/tcp # Bloomberg locator
blp5 48129/udp # Bloomberg locator
com-bardac-dw 48556/tcp # com-bardac-dw
com-bardac-dw 48556/udp # com-bardac-dw
iqobject 48619/tcp # iqobject
iqobject 48619/udp # iqobject
===
END......
- 計算文本中第 2 字段(假設是數字)的總和:
awk '{sum += $2} END{print "總和:"sum}' /tmp/services
四、三劍客功能對比與適用場景
工具 | 核心優勢 | 適用場景 | 特點 |
grep | 快速過濾文本行 | 日志檢索、關鍵詞匹配、篩選行 | 功能單一,僅 “過濾”,不修改內容 |
sed | 批量修改文本 | 字符串替換、行刪除 / 添加、格式調整 | 按 “行” 處理,適合簡單修改,不擅長字段運算 |
awk | 字段處理與數據統計 | 字段提取、數據計算、報表生成、條件判斷 | 按 “字段” 處理,支持編程邏輯,功能最全面 |
總結:簡單篩選用 grep,批量修改用 sed,復雜字段處理或統計用 awk,實際場景中三者常結合使用(如 grep 篩選后用 sed 修改,再用 awk 統計)。