Shell編程筆記之正則表達式與文本處理器詳解
一、引言
在 Shell 編程領域,正則表達式與文本處理器是極為關鍵的工具。正則表達式憑借其強大的字符串匹配能力,可精準定位符合特定規(guī)則的字符串;而 grep、sed、awk 等文本處理器,能高效處理文本內容,滿足各類文本處理需求。掌握這些知識,對編寫高效、靈活的 Shell 腳本意義重大,本筆記將深入學習相關內容。
二、正則表達式
2.1 定義與用途
正則表達式(Regular Expression,簡稱 RE),又稱正規(guī)表達式、常規(guī)表達式,在代碼中常簡寫為 regex、regexp 或 RE。它是用單個字符串描述、匹配一系列符合特定句法規(guī)則字符串的方法,在腳本編程、文本編輯器及多種編程語言中都占據核心地位。在 Shell 編程里,可利用正則表達式進行文本的查找、刪除、替換等操作,提升文本處理效率。
2.2 基礎正則表達式
學習基礎正則表達式,需借助測試文件 test.txt,其內容如下:
he was short and fat. He was wearing a blue polo shirt with black pants.The home of Football on BBC Sport online. the tongue is boneless but it breaks bones.12! google is the best tools for search keyword. The year ahead will test our political establishment to the limit. P1=3.141592653589793238462643383249901429 a wood cross! Actions speak louder than words #woood # #woooooood # Axy zxyzxyzxyzC I bet this place is really spooky late at night! Misfortunes never come alone/single. I shouldn't have lett so tast.
2.2.1 查找特定字符
使用 grep 命令查找特定字符。-n
選項用于顯示行號,-i
選項表示不區(qū)分大小寫,-v
選項實現反向選擇(查找不包含指定字符的行)。
- 查找 “the” 所在位置:
[root@localhost ~]# grep -n 'the' test.txt 4:the tongue is boneless but it breaks bones.12! 5:google is the best tools for search keyword. 6:The year ahead will test our political establishment to the limit.
- 不區(qū)分大小寫查找 “the”:
[root@localhost ~]# grep -in 'the' test.txt 3:The home of Football on BBC Sport online. 4:the tongue is boneless but it breaks bones.12! 5:google is the best tools for search keyword. 6:The year ahead will test our political establishment to the limit.
- 查找不包含 “the” 的行:
[root@localhost ~]# grep -vn 'the' test.txt 1:he was short and fat. 2:He was wearing a blue polo shirt with black pants. 3:The home of Football on BBC Sport online. 7:p13.141592653589793238462643383249901429 8:a wood cross! 9:Actions speak louder than words 10: 11:#woood # 12:#wo0000ood # 13:AxyzxyzxyzxyzC 14:I bet this place is really spooky late at night! 15:Misfortunes never come alone/single. 16:I shouldn't have lett so tast.
2.2.2 利用中括號 “[]” 查找集合字符
“[]” 內的多個字符僅代表一個字符。
- 查找 “shirt” 與 “short”:
[root@localhost ~]# grep -n 'sh[io]rt' test.txt 1:he was short and fat. 2:He was wearing a blue polo shirt with black pants.
- 查找包含重復單個字符 “oo” 的字符串:
[root@localhost ~]# grep -n 'oo' test.txt 3:The home of Football on BBC Sport online. 5:google is the best tools for search keyword. 8:a wood cross! 11:#woood # 12:#woo00oood # 14:I bet this place is really spooky late at night!
- 查找 “oo” 前面不是 “w” 的字符串:
[root@localhost ~]# grep -n '[^w]oo' test.txt 3:The home of Football on BBC Sport online. 5:google is the best tools for search keyword. 11:#woood # 12:#wooo0oood # 14:I bet this place is really spoky late at night!
- 查找不希望 “oo” 前面存在小寫字母的字符串:
[root@localhost ~]# grep -n '[^a-z]oo' test.txt 3:The home of Football on BBC Sport online.
- 查找包含數字的行:
[root@localhost ~]# grep -n '[0-9]' test.txt 4:the tongue is boneless but it breaks bones.12! 7:PI=3.141592653589793238462643383249901429
2.2.3 查找行首 “^” 與行尾字符 “$”
“^” 表示行首,“$” 表示行尾。
- 查找以 “the” 為行首的行:
[root@localhost ~]# grep -n '^the' test.txt 4:the tongue is boneless but it breaks bones.12!
- 查找以小寫字母開頭的行:
[root@localhost ~]# grep -n '^[a-z]' test.txt 1:he was short and fat. 4:the tongue is boneless but it breaks bones.12! 5:google is the best tools for search keyword. 8:a wood cross!
- 查找以大寫字母開頭的行:
[root@localhost ~]# grep -n '^[A-Z]' test.txt 2:He was wearing a blue polo shirt with black pants. 3:The home of Football on BBC Sport online. 6:The year ahead will test our political establishment to the limit. 7:PI=3.141592653589793238462643383249901429 9:Actions speak louder than words 13:AxyzxyzxyzxyzC 14:I bet this place is really spooky late at night! 15:Misfortunes never come alone/single. 16:I shouldn't have lett so tast.
- 查找不以字母開頭的行:
[root@localhost ~]# grep -n '^[^a-zA-Z]' test.txt 11:#woood # 12:#woo000ood #
- 查找以小數點 “.” 結尾的行(“.” 是元字符,需用 “\” 轉義):
[root@localhost ~]# grep -n '\.$' test.txt 1:he was short and fat. 2:He was wearing a blue polo shirt with black pants. 3:The home of Football on BBC Sport online. 5:google is the best tools for search keyword. 6:The year ahead will test our political establishment to the limit. 15:Misfortunes never come alone/single. 16:I shouldn't have lett so tast.
- 查找空白行:
[root@localhost ~]# grep -n '^$' test.txt 10:
2.2.4 查找任意一個字符 “.” 與重復字符 “*”
“.” 代表任意一個字符,“*” 代表重復零個或多個前面的單字符。
- 查找 “w??d” 的字符串:
[root@localhost ~]# grep -n 'w..d' test.txt 5:google is the best tools for search keyword. 8:a wood cross! 9:Actions speak louder than words
- 查找包含至少兩個 “o” 以上的字符串:
[root@localhost ~]# grep -n 'ooo*' test.txt 3:The home of Football on BBC Sport online. 5:google is the best tools for search keyword. 8:a wood cross! 11:#woood # 12:#woo00oood # 14:I bet this place is really spooky late at night!
- 查找以 “w” 開頭 “d” 結尾,中間包含至少一個 “o” 的字符串:
[root@localhost ~]# grep -n 'woo*d' test.txt 8:a wood cross! 11:#woood # 12:#woooooood #
- 查找以 “w” 開頭 “d” 結尾,中間字符可有可無的字符串:
[root@localhost ~]# grep -n 'w.*d' test.txt 1:he was short and fat. 5:google is the best tools for search keyword. 8:a wood cross! 9:Actions speak louder than words 11:#woood # 12:#woo00oood #
- 查找任意數字所在行:
[root@localhost ~]# grep -n '[0-9][0-9]*' test.txt 4:the tongue is boneless but it breaks bones.12! 7:PI=3.141592653589793238462643383249901429
2.2.5 查找連續(xù)字符范圍 “{}”
“{}” 用于限制重復字符串的范圍,在 Shell 中使用需轉義。
- 查找兩個 “o” 的字符:
[root@localhost ~]# grep -n 'o\{2\}' test.txt 3:The home of Football on BBC Sport online. 5:google is the best tools for search keyword. 8:a wood cross! 11:#woood # 12:#wo0000ood # 14:I bet this place is really spooky late at night!
- 查找以 “w” 開頭以 “d” 結尾,中間包含 2 - 5 個 “o” 的字符串:
[root@localhost ~]# grep -n 'wo\{2,5\}d' test.txt 8:a wood cross! 11:#woood #
- 查找以 “w” 開頭以 “d” 結尾,中間包含 2 個或 2 個以上 “o” 的字符串:
[root@localhost ~]# grep -n 'wo\{2,\}d' test.txt 8:a wood cross! 11:#woood # 12:#woo00oood #
2.3 元字符總結
字符 | 描述 |
\ | 將下一個字符標記為一個特殊字符、或一個原義字符、或一個 向后引用、或一個八進制轉義符。例如,'n' 匹配字符 "n"。'\n' 匹配一個換行符。序列 '\\' 匹配 "\" 而 "\(" 則匹配 "("。 |
^ | 匹配輸入字符串的開始位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 也匹配 '\n' 或 '\r' 之后的位置。 |
$ | 匹配輸入字符串的結束位置。如果設置了RegExp 對象的 Multiline 屬性,$ 也匹配 '\n' 或 '\r' 之前的位置。 |
* | 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。* 等價于{0,}。 |
+ | 匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價于 {1,}。 |
? | 匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 。? 等價于 {0,1}。 |
{n} | n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。 |
{n,} | n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價于 'o+'。'o{0,}' 則等價于 'o*'。 |
{n,m} | m 和 n 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價于 'o?'。請注意在逗號和兩個數之間不能有空格。 |
? | 當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對于字符串 "oooo",'o+?' 將匹配單個 "o",而 'o+' 將匹配所有 'o'。 |
. | 匹配除換行符(\n、\r)之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用像"(.|\n)"的模式。 |
(pattern) | 匹配 pattern 并獲取這一匹配。所獲取的匹配可以從產生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中則使用 $0…$9 屬性。要匹配圓括號字符,請使用 '\(' 或 '\)'。 |
(?:pattern) | 匹配 pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以后使用。這在使用 "或" 字符 (|) 來組合一個模式的各個部分是很有用。例如, 'industr(?:y|ies) 就是一個比 'industry|industries' 更簡略的表達式。 |
(?=pattern) | 正向肯定預查(look ahead positive assert),在任何匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如,"Windows(?=95|98|NT|2000)"能匹配"Windows2000"中的"Windows",但不能匹配"Windows3.1"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發(fā)生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。 |
(?!pattern) | 正向否定預查(negative assert),在任何不匹配pattern的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如"Windows(?!95|98|NT|2000)"能匹配"Windows3.1"中的"Windows",但不能匹配"Windows2000"中的"Windows"。預查不消耗字符,也就是說,在一個匹配發(fā)生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。 |
(?<=pattern) | 反向(look behind)肯定預查,與正向肯定預查類似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。 |
(?<!pattern) | 反向否定預查,與正向否定預查類似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。 |
x|y | 匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food"。 |
[xyz] | 字符集合。匹配所包含的任意一個字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。 |
[^xyz] | 負值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'、'l'、'i'、'n'。 |
[a-z] | 字符范圍。匹配指定范圍內的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范圍內的任意小寫字母字符。 |
[^a-z] | 負值字符范圍。匹配任何不在指定范圍內的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范圍內的任意字符。 |
\b | 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
\B | 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
\cx | 匹配由 x 指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字符。 |
\d | 匹配一個數字字符。等價于 [0-9]。 |
\D | 匹配一個非數字字符。等價于 [^0-9]。 |
\f | 匹配一個換頁符。等價于 \x0c 和 \cL。 |
\n | 匹配一個換行符。等價于 \x0a 和 \cJ。 |
\r | 匹配一個回車符。等價于 \x0d 和 \cM。 |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。 |
\S | 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。 |
\t | 匹配一個制表符。等價于 \x09 和 \cI。 |
\v | 匹配一個垂直制表符。等價于 \x0b 和 \cK。 |
\w | 匹配字母、數字、下劃線。等價于'[A-Za-z0-9_]'。 |
\W | 匹配非字母、數字、下劃線。等價于 '[^A-Za-z0-9_]'。 |
2.4 擴展正則表達式
擴展正則表達式可簡化指令,grep 命令僅支持基礎正則表達式,使用擴展正則表達式需用 egrep 或 awk 命令。egrep 命令與 grep 用法相似,可搜索文件中的任意字符串和符號。
元字符 | 含義 | 示例及解釋 |
---|---|---|
+ | 匹配前面的子表達式一次或多次,即至少出現一次。 | 模式 go+gle 能匹配 google 、gooogle 等,但無法匹配 gle 。 |
? | 匹配前面的子表達式零次或一次,也就是該字符可有可無。 | 模式 colou?r 能匹配 color 和 colour 。 |
| | 表示或關系,用于匹配多個選擇中的任意一個。 | 模式 cat|dog 可以匹配 cat 或者 dog 。 |
() | 用于分組,將多個字符組合成一個整體,便于后續(xù)操作,還可用于后向引用。 | 模式 (ab)+ 能匹配 ab 、abab 等;(\d{3})-(\d{4}) 可將電話號碼分為區(qū)號和號碼兩部分,方便后續(xù)引用。 |
{m,n} | 指定前面的子表達式出現的次數范圍,m 是下限,n 是上限,都為非負整數且 m <= n。若省略 m,則表示 0 到 n 次;若省略 n,則表示至少 m 次。 | 模式 a{2,4} 能匹配 aa 、aaa 、aaaa ;a{3,} 能匹配 aaa 、aaaa 等。 |
例如,查詢除文件中空白行與行首為 “#” 之外的行,基礎正則表達式需用管道命令搜索兩次:
[root@localhost ~]# grep -v '^$' test.txt|grep -v '^#'
擴展正則表達式可簡化為:
[root@localhost ~]# egrep -v '^$|^#' test.txt
三、文本處理器
3.1 sed 工具
sed(Stream EDitor)是強大且簡單的文本解析轉換工具,可讀取文本并編輯,廣泛應用于 Shell 腳本。
3.1.1 工作流程
sed 工作流程包括讀取、執(zhí)行和顯示三個過程:
- 讀取:從輸入流(文件、管道、標準輸入)讀取一行內容到臨時緩沖區(qū)(模式空間)。
- 執(zhí)行:默認在模式空間順序執(zhí)行 sed 命令,除非指定行地址,否則在所有行依次執(zhí)行。
- 顯示:將修改后的內容發(fā)送到輸出流,發(fā)送后清空模式空間。該過程重復直至所有內容處理完。默認情況下,輸入文件不會改變,除非用重定向存儲輸出。
3.1.2 命令選項
常見 sed 命令選項:
選項 | 完整形式 | 說明 |
---|---|---|
-e | --expression= | 用指定命令或腳本來處理輸入文本文件 |
-f | --file= | 用指定的腳本文件來處理輸入文本文件 |
-h | --help | 顯示幫助 |
-n | --quiet、silent | 僅顯示處理后的結果 |
-i | 無 | 直接編輯文本文件 |
3.1.3 操作命令
“操作” 指定對文件的動作行為,格式通常為 “[n1 [,n2]] 操作參數”,n1、n2 可選,代表操作的行數。常見操作:
操作 | 說明 |
---|---|
a | 在當前行下面增加一行指定內容 |
c | 將選定行替換為指定內容 |
d | 刪除選定的行 |
i | 在選定行上面插入一行指定內容 |
p | 指定行則打印指定行,不指定則打印所有內容,有非打印字符以 ASCII 碼輸出,常與 “-n” 選項一起使用 |
s | 替換指定字符 |
y | 字符轉換 |
3.1.4 用法示例
以 test.txt 文件為例:
輸出符合條件的文本:
輸出所有內容:
[root@localhost ~]# sed -n 'p' test.txt
輸出第 3 行:
[root@localhost ~]# sed -n '3p' test.txt
輸出 3 - 5 行:
[root@localhost ~]# sed -n '3,5p' test.txt
輸出所有奇數行:
[root@localhost ~]# sed -n 'p;n' test.txt
輸出所有偶數行:
[root@localhost ~]# sed -n 'n;p' test.txt
輸出第 1 - 5 行之間的奇數行:
[root@localhost ~]# sed -n '1,5{p;n}' test.txt
輸出第 10 行至文件尾之間的偶數行:
[root@localhost ~]# sed -n '10,${n;p}' test.txt
輸出包含 “the” 的行:
[root@localhost ~]# sed -n '/the/p' test.txt
輸出從第 4 行至第一個包含 “the” 的行:
[root@localhost ~]# sed -n '4,/the/p
3.2 awk 工具
3.2.1 awk 工具概述與命令格式
awk 是功能強大的編輯工具,逐行讀取文本,根據匹配模式查找、格式化輸出或過濾處理。命令格式為:
awk選項'模式或條件{編輯指令}'文件1文件2... awk -f腳本文件文件1文件2...
awk 傾向于將一行分成多個 “字段” 處理,默認字段分隔符為空格或 tab 鍵,可使用邏輯操作符和進行數學運算。
3.2.2 awk 內建變量
FS | 指定每行文本的字段分隔符,默認為空格或制表位 |
NF | 當前處理的行的字段個數 |
NR | 當前處理的行的行號(序數) |
$0 | 當前處理的行的整行內容 |
$n | 當前處理行的第 n 個字段(第 n 列) |
FILENAME | 被處理的文件名 |
RS | 數據記錄分隔,默認為\n ,即每行為一條記錄 |
3.2.3 awk 用法示例
按行輸出文本:輸出所有內容:
awk '{print}' test.txt awk '{print $0}' test.txt
輸出第 1 - 3 行內容:
awk 'NR==1, NR==3{print}' test.txt awk '(NR>=1)&&(NR<=3){print}' test.txt
總結
到此這篇關于Shell編程筆記之正則表達式與文本處理器的文章就介紹到這了,更多相關Shell正則表達式與文本處理器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
linux生成(加載)動態(tài)庫靜態(tài)庫和加載示例方法
這篇文章主要介紹了linux生成(加載)動態(tài)庫靜態(tài)庫示例方法,大家參考使用2013-11-11shell監(jiān)控linux系統(tǒng)進程創(chuàng)建腳本分享
shell監(jiān)控linux系統(tǒng)進程創(chuàng)建腳本,大家參考使用吧2013-12-12linux shell 中數組的定義和for循環(huán)遍歷的方法
今天小編就為大家分享一篇linux shell 中數組的定義和for循環(huán)遍歷的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06