目錄
前言
一、正則表達式
(一)定義與用途
(二)基礎正則表達式
(三)基礎正則表達式元字符
(四)擴展正則表達式
二、文本處理器:Shell 編程的得力助手
(一)sed 工具
(二)awk 工具
前言
在 Shell 編程領域,正則表達式與文本處理器是極為關鍵的技術,對于系統管理員、開發人員以及數據分析師而言,熟練掌握這些技能,能夠顯著提升文本處理的效率和準確性,為編寫高效、靈活的 Shell 腳本奠定堅實基礎。
一、正則表達式
(一)定義與用途
正則表達式(Regular Expression,簡稱 RE),又被稱作正規表達式、常規表達式,在代碼中常簡寫為 regex、regexp。它是一種利用單個字符串來描述、匹配一系列符合特定句法規則字符串的強大工具 。在 Shell 編程中,正則表達式主要用于文本的查找、替換、刪除等操作,廣泛應用于文本編輯器、程序設計語言以及各類數據處理場景。
(二)基礎正則表達式
為深入理解基礎正則表達式,我們準備一個名為 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.
- 查找特定字符:使用 grep 命令結合正則表達式可實現特定字符的查找。
例如,執行 “grep -n 'the' test.txt”,“-n” 選項用于顯示行號,該命令會在 test.txt 文件中查找包含 “the” 的行,并輸出行號及匹配行內容 。若加上 “-i” 選項,即 “grep -in 'the' test.txt”,則表示不區分大小寫進行查找。若要反向選擇,查找不包含 “the” 字符的行,可使用 “grep -vn 'the' test.txt”,“-v” 選項表示反向匹配。
- 利用中括號查找集合字符:中括號 “[]” 在正則表達式中用于匹配集合內的任意一個字符。
比如,查找 “shirt” 與 “short” 這兩個字符串,可執行 “grep -n'sh [io] rt' test.txt” ,因為 “[io]” 表示匹配 “i” 或者 “o”。查找包含重復單個字符 “oo” 的行,執行 “grep -n 'oo' test.txt”。若要查找 “oo” 前面不是 “w” 的字符串,可使用集合字符的反向選擇 “[^]”,即 “grep -n '[^w] oo' test.txt”。查找包含數字的行,執行 “grep -n '[0-9]' test.txt”。
- ** 查找行首 “^” 與行尾字符 “:表示行首,” 表示行尾。
“grep -n '^the' test.txt” #查詢以 “the” 字符串為行首的行
“grep -n '^[a-z]' test.txt” #查詢以小寫字母開頭的行
“grep -n '^[A-Z]' test.txt” #查詢大寫字母開頭的行
“grep -n '[a-zA-Z]' test.txt” #查詢不以字母開頭的行
“grep -n '^$' test.txt” #查詢空白行
查找以小數點 “.” 結尾的行時,由于小數點在正則表達式中是元字符,需使用轉義字符 “\”,即 “grep -n '.' test.txt”。
- 查找任意一個字符 “.” 與重復字符 “*”:在正則表達式中,小數點 “.” 代表任意一個字符(除換行符外)。
例如,執行 “grep -n 'w..d' test.txt”,可查找以 “w” 開頭、“d” 結尾且中間有兩個任意字符的字符串。“” 代表重復零個或多個前面的單字符。如 “grep -n 'oo' test.txt”,“oo*” 表示第一個 “o” 必須存在,第二個 “o” 則是零個或多個 “o”。若查詢包含至少兩個 “o” 以上的字符串,執行 “grep -n 'ooo*' test.txt”。查詢以 “w” 開頭 “d” 結尾,中間包含至少一個 “o” 的字符串,執行 “grep -n 'woo*d' test.txt”;查詢以 “w” 開頭 “d” 結尾,中間的字符可有可無的字符串,執行 “grep -n 'w.d' test.txt”。查詢任意數字所在行,執行 “grep -n '[0-9][0-9]' test.txt”。
- 查找連續字符范圍 “{}”:“{}” 用于限制重復字符的范圍,在 Shell 中使用時需用轉義字符 “\”。
例如:
“grep -n 'o {2}' test.txt” #查詢兩個 “o” 的字符
“grep -n 'wo {2,5} d' test.txt” #查詢以 “w” 開頭以 “d” 結尾,中間包含 2 - 5 個 “o” 的字符串
“grep -n 'wo {2,} d' test.txt” #查詢以 “w” 開頭以 “d” 結尾,中間包含 2 個或 2 個以上 “o” 的字符串
(三)基礎正則表達式元字符
常見的基礎正則表達式元字符如下表所示:
字符 | 說明 |
| | 將 | 前命令的輸出作為 | 后命令的輸入 |
^ | 匹配輸入字符串的開始位置 |
$ | 匹配輸入字符串的結束位置 |
* | 匹配前面的子表達式零次或多次 |
+ | 匹配前面的子表達式一次或多次 |
? | 匹配前面的子表達式零次或一次 |
. | 匹配除換行符(\n、\r)之外的任何單個字符 |
[a - z] | 字符范圍。匹配指定范圍內的任意字符 |
{n} | n 是一個非負整數,匹配確定的 n 次 |
{n,} | n 是一個非負整數,至少匹配 n 次 |
{n,m} | m 和 n 均為非負整數,其中 n <= m。最少匹配 n 次且最多匹配 m 次 |
\d | 匹配一個數字字符。等價于 [0 - 9] |
\D | 匹配一個非數字字符。等價于 [^0 - 9] |
\s | 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [\n\t\v] |
\S | 匹配任何非空白字符。等價于 [^\n\t\v] |
\w | 匹配字母、數字、下劃線。等價于 '[A - Za - z0 - 9_]' |
\W | 匹配非字母、數字、下劃線,等價于 '[^A - Za - z0 - 9_]' |
\n | 匹配一個換行符 |
\r | 匹配一個換頁符 |
\v | 匹配一個回車符 |
(四)擴展正則表達式
在某些場景下,為簡化指令,可使用擴展正則表達式。例如,查看生效的配置文件(排除空白行與行首為 “#” 的行),使用基礎正則表達式需執行 “grep -v '^' test.txt|grep -v '^\#'”,而使用擴展正則表達式,可簡化為“egrep -v '^|^#' test.txt”,其中單引號內的管道符號 “|” 表示 “或者(or)” 。grep 命令僅支持基礎正則表達式,若使用擴展正則表達式,需使用 egrep 或 awk 命令。egrep 命令與 grep 命令用法基本相似,可用于搜索文件中的任意字符串和符號。
擴展正則表達式常見元字符如下:
元字符 | 作用與示例 |
+ | 重復一個或者一個以上的前一個字符。 |
? | 零個或者一個的前一個字符。 |
** | 使用或者(or)的方式找出多個字符。 |
() | 查找 “組” 字符串。 |
()+ | 辨別多個重復的組。 |
二、文本處理器:Shell 編程的得力助手
在 Linux/UNIX 系統中,grep、sed、awk 被稱為 Shell 編程的 “三劍客”,下面重點介紹 sed 和 awk 這兩個強大的文本處理器。
(一)sed 工具
sed(Stream EDitor)是一款強大且簡單的文本解析轉換工具,可讀取文本,并依據指定條件對文本內容進行編輯(如刪除、替換、添加、移動等),最后輸出所有行或僅輸出處理后的某些行。sed 常用于 Shell 腳本,以完成各種自動化處理任務。
- 工作流程與命令選項:sed 的工作流程包含讀取、執行和顯示三個過程。讀取時,sed 從輸入流(文件、管道、標準輸入)讀取一行內容并存儲到臨時緩沖區(模式空間);執行階段,默認所有 sed 命令在模式空間順序執行,除非指定行地址;顯示過程則將修改后的內容發送到輸出流,之后模式空間被清空。常見的 sed 命令選項包括:“-e” 或 “-expression=”,用于指定命令或腳本來處理輸入文本文件;“-f” 或 “-file=”,表示用指定的腳本文件處理輸入文本文件;“-h” 或 “--help”,用于顯示幫助信息;“-n”、“--quiet” 或 “silent”,僅顯示處理后的結果;“-i”,直接編輯文本文件。
- 用法示例:以 test.txt 文件為例:
“sed -n 'p' test.txt” #可輸出所有內容,等同于 “cat test.txt”;
“sed -n '3p' test.txt” #輸出第 3 行;
“sed -n '3,5p' test.txt” #輸出 3 - 5 行。
結合正則表達式時:
“sed -n '/the/p' test.txt” #輸出包含 “the” 的行;
“sed -n '/the/=' test.txt” #輸出包含 “the” 的行所在的行號。
在刪除操作方面,如:
“sed '3d'” #刪除第 3 行;
“sed '3,5d'” #刪除 3 - 5 行;
“sed '/cross/d'” #刪除包含 “cross” 的行。
“sed '/^[a - z]/d' test.txt” #刪除以小寫字母開頭的行
“sed '/./d' test.txt” #刪除以 “.” 結尾的行
“sed -e '/^/{n;/^/d}' test.txt” #刪除重復的空行 其效果與“cat -s test.txt”相同
替換操作中:
“sed 's/the/THE/' test.txt” #將每行中的第一個“the”替換為“THE”;
“sed 's/the/THE/g' test.txt” #將文件中的所有“the”替換為“THE”;
“sed 's/o//g' test.txt” #將文件中的所有“o”刪除(替換為空串)。
遷移操作時:
“sed '/the/{H;d};G' test.txt” #將包含 “the” 的行遷移至文件末尾;
“sed '/the/w out.file' test.txt” #將包含 “the” 的行另存為文件 out.file。
此外,復雜操作可通過腳本文件實現。例如,將第 1 - 5 行內容轉移至第 17 行后,可先創建腳本文件 opt.list,內容為 “1,5H”“1,5d”“17G”,再執行 “sed -f opt.list test.txt”。
- 案例:編寫腳本調整 vsftpd 服務配置,禁止匿名用戶,允許本地用戶(也允許寫入)。示例腳本如下:
#!/bin/bash
# 指定樣本文件路徑、配置文件路徑
SAMPLE="/usr/share/doc/vsftpd - 3.0.2/EXAMPLE/INTERNET_SITE/vsftpd.conf"
CONFIG="/etc/vsftpd/vsftpd.conf"
# 備份原來的配置文件,檢測文件名為/etc/vsftpd/vsftpd.conf.bak備份文件是否存在,若不存在則使用cp命令進行文件備份
[! -e "$CONFIG.bak" ] && cp $CONFIG $CONFIG.bak
# 基于樣本配置進行調整,覆蓋現有文件
sed -e '/anonymous_enable/s/YES/NO/g' $SAMPLE > $CONFIG
sed -i -e '/^local_enable/s/NO/YES/g' -e '/write_enable/s/NO/YES/g' $CONFIG
grep "listen" $CONFIG || sed -i '\alisten=YES' $CONFIG
# 啟動vsftpd服務,并設為開機后自動運行
systemctl restart vsftpd
systemctl enable vsftpd
(二)awk 工具
awk 是 Linux/UNIX 系統中功能強大的編輯工具,可逐行讀取輸入文本,根據指定的匹配模式進行查找,對符合條件的內容進行格式化輸出或過濾處理,廣泛應用于 Shell 腳本以完成自動化配置任務。
- 命令格式與基本概念:awk 的命令格式為:
“awk 選項 ' 模式或條件 {編輯指令}' 文件 1 文件 2...”,也可通過 “-f” 讀取腳本對目標文件進行處理。
awk 傾向于將一行分成多個 “字段” 進行處理,默認字段分隔符為空格或 tab 鍵,執行結果可通過 print 功能打印顯示。awk 還支持邏輯操作符:“&&”(表示 “與”)、“||”(表示 “或”)、“!”(表示 “非”)以及簡單的數學運算(如 +、-、*、/、%、^ 分別表示加、減、乘、除、取余和乘方)。
awk 包含幾個特殊的內建變量:
- FS(指定每行文本的字段分隔符,默認為空格或制表位)
- NF(當前處理的行的字段個數)
- NR(當前處理的行的行號)
- $0(當前處理的行的整行內容)
- $n(當前處理行的第 n 個字段)
- FILENAME(被處理的文件名)
- RS(數據記錄分隔,默認為 \n,即每行為一條記錄)
- 用法示例:按行輸出文本時:
“awk '{print}' test.txt” #或 “awk '{print 0}' test.txt”輸出所有內容
“awk 'NR1,NR3{print}' #test.txt”輸出1 - 3行內容
“awk 'BEGIN {x=0};/\/bin\/bash/{x++};END {print x}' /etc/passwd” #統計以 “/bin/bash” 結尾的行數。
按字段輸出文本時:
“awk '{print $3}' test.txt” #輸出每行中(以空格或制表位分隔)的第3個字段
“awk -F ":" '$7~"/bash"{print $1}' /etc/passwd” #輸出以冒號分隔且第 7 個字段中包含 “/bash” 的行的第 1 個字段。