iT邦幫忙

2024 iThome 鐵人賽

DAY 25
0

對應 30天挑戰精通 PowerShell 該書第 21 章。

正規表示式( regular expression )有時也稱為 regex,在文字解析( text parsing )方面非常實用,這在 UNIX 和 Linux 作業系統裡是常有的需求。而在 PowerShell 中,你進行文字解析的頻率通常較低,需要用到 regex 的情況也相對較少。話雖如此,我們清楚地知道,在 PowerShell 中,有時你需要解析像日誌檔案( log file )這樣的文字內容。這正是本章介紹正規表示式的方法:作為解析文字檔的工具
Reference - P.331

最早接觸正規表示式是透過 Python 學習的,這次本來也打算在 Regex101 上進行一些線上測試。結果沒想到,頁面上竟然沒有 PowerShell 的選項!後來查了一下,發現其實可以使用 .NET 7.0 (C#) 來操作,因為 PowerShell 和 C# 都是基於 .NET framework 的正規表示式引擎,不過可能在這幾個區塊需要特別注意:

  1. 轉義字符( Escape Characters )
    PowerShell 因是 shell 語言,所以對某些字符的處理方式不同。例如,反引號(``)在 PowerShell 中用來轉義字符,而在正則表達式中則是使用反斜線(\)來轉義。這可能會引發混淆,或在使用正則表達式時需要額外的轉義。
  2. 多行模式和單行模式( Multiline and Singleline Modes )
    PowerShell 的 -match 運算符會自動假設是多行模式,因此使用 ^ 和 $ 的模式會匹配每一行的開頭和結尾,而不是整個字串。
  3. 大小寫敏感性( Case Sensitivity )
    預設情況下,PowerShell 的 -match 運算符是不區分大小寫的。

21.1 正規表示式的目的

目的:找出大型文字檔中的特定模式

正規表示式 (regex) 的主要功能是用來在文字中找到符合特定規則或模式的資料。打個比方,在一個
Case 裡,有一個日誌檔案,我們需要從中找出所有發生錯誤的記錄,或者過濾出某些特定的時間段裡的資訊時,就可以使用正規表示式來過濾。

這讓我想到一個類似的比喻,你可以想像當你在圖書館找書時,正規表示式就像是你在搜尋分類號、書名或作者的一套非常靈活的規則,它幫助你篩選並快速找到你想要的書。

而在 PowerShell 中,正規表示式可以用來掃描文字檔案中的內容,找出特定的文字組合。比如,你可以找出符合日期格式的所有行,或找出包含特定關鍵字的行。這在處理大型日誌檔案時尤其實用。


21.2 正規表示式語法入門

特殊字元與基本語法

正規表示式有一些特殊的字元,它們用來表示不同的匹配規則。這些特殊字元讓你能夠靈活地尋找文字模式,以下是一些常見的正規表示式語法:

字元 說明 範例
. 任意一個字元 a.b 可匹配 "acb", "a2b"
\* 重複前面的字元零次或多次 ab\* 可匹配 "a", "ab", "abbb"
\d 任何一個數字 \d{3} 可匹配三個連續數字
\D 任何一個非數字字符 \D 可匹配 "a", "!", 但不匹配 "3"
\s 空白字符 a\s+b 可匹配 "a b", "a b"
\w 任何一個字母、數字或底線 \w+ 可匹配 "hello", "a1_23"
\W 任何一個非字母、數字或底線 \W 可匹配 "!", "@", "#", 但不匹配 "a" 或 "3"
[abc] 匹配括號內的任一字元 [aeiou] 可匹配任一母音字母
[a-z] 匹配小寫字母 a 到 z 中任一字元 [a-z] 可匹配任一小寫字母
[^abcde] 匹配不在括號內的字元 [^aeiou] 可匹配任一非母音字母
^ 行首匹配 ^Error 可匹配 "Error" 開頭的行
$ 行尾匹配 done$ 可匹配以 "done" 結尾的行
? 前面的字元可出現零次或一次 colou?r 可匹配 "color" 或 "colour"
{2} 前面的字元出現兩次 \d{2} 可匹配兩位數字,如 "42"
\ 跳脫特殊字元,使其作為普通字元 \. 可匹配一個句點 ".",而不是任意字元

透過這些符號,你可以組合出極其複雜的模式,用於尋找各種格式的資料。例如,要從文字檔中找出所有電話號碼,你可以用正規表示式 \d{3}-\d{3}-\d{4},這樣的語法會匹配類似 "123-456-7890" 的格式。
Reference - about_Regular_Expressions


21.3 搭配 -Match 使用正規表示式

使用 -Match 來比較並找到匹配

-Match 是 PowerShell 中用於匹配正規表示式的比較運算子。這個運算子能讓你快速地檢查某個字串是否符合特定的正規表示式規則,並返回布林值 ($true$false)。

書中範例

https://ithelp.ithome.com.tw/upload/images/20241009/20168708cxDNpa14It.png

範例一解釋:

"car" -match "c[aeiou]r"
  • 正規表示式 "c[aeiou]r" 表示要匹配一個字串,這個字串的結構是:
    1. 以字母 c 開頭。
    2. 接著是任意一個母音字母( a, e, i, o, u)。
    3. 最後以字母 r 結尾。
  • "car" 完全符合這個模式: c + a + r,所以結果是 True

範例二解釋:

"caaar" -match "c[aeiou]r"
  • "c[aeiou]r" 只會匹配由 c 開頭、一個母音、再加上 r 的結構。
  • "caaar" 有三個 a 字母,但正規表示式只期望中間有一個母音字母。因此,這個字串不符合條件,結果是 False

範例三解釋:

"caaar" -match "c[aeiou]+r"
  • 正規表示式 "c[aeiou]+r" 表示要匹配:
    1. c 開頭。
    2. 接著是一個或多個母音( [aeiou]+ 中的 + 表示前面的字符可以重複一次或多次)。
    3. 最後以 r 結尾。
  • "caaar" 的結構是 c + aaa + r,中間有三個 a,符合一個或多個母音的條件,因此結果是 True

範例四解釋:

"cjinr" -match "c[aeiou]+r"
  • "c[aeiou]+r" 要求在 cr 之間必須有一個或多個母音( a, e, i, o, u )。
  • "cjinr" 中間的部分是 jin,這部分不包含符合條件的母音序列。因此,這個字串不符合正規表示式,結果是 False。

範例五解釋:

"cear" -match "c[aeiou]r"
  • "c[aeiou]r" 要求:
    1. c 開頭。
    2. 接著是一個母音a, e, i, o, u)。
    3. 最後是 r
  • "cear" 中間的部分是 ea,這不符合只要一個母音的條件。因此,這個字串不符合模式,結果是 False

範例 - 透過 script 用正規表示式尋找 Error

chapter21_exmaple_log.txt 內容

Info: System started successfully.
Error: Unable to connect to server.
Warning: Low disk space.
Error: 404 - Not Found.
Error: 500 - Internal Server Error.
Info: User login successful.

script - chapter21_parseLog.ps1

# 設定日誌檔案的路徑
$logFilePath = "/Users/kanglin/code/30days/chapter21_exmaple_log.txt"

# 確認日誌檔案是否存在
if (-not (Test-Path -Path $logFilePath)) {
    Write-Output "日誌檔案不存在:$logFilePath"
    exit
}

# 讀取日誌檔案內容
$logContent = Get-Content -Path $logFilePath

# 遍歷日誌內容並找出包含 "Error" 的行
foreach ($line in $logContent) {
    # 使用 -match 匹配包含 "Error" 的行
    if ($line -match "Error") {
        # 進一步檢查錯誤代碼的格式,例如 "Error: 404"
        if ($line -match "Error:\s*\d{3}") {
            # 輸出符合錯誤代碼格式的行
            Write-Output "找到錯誤行: $line"
        } else {
            # 只包含 "Error" 的行
            Write-Output "找到一般錯誤行: $line"
        }
    }
}

Result

https://ithelp.ithome.com.tw/upload/images/20241009/20168708ID1OF3bupk.png


21.4 搭配 Select-String 使用正規表示式

Select-String:PowerShell 的文字搜尋利器

Select-String 是 PowerShell 中專門用於搜尋檔案或輸入中的文字的 cmdlet,功能類似於 UNIX/Linux 系統中的 grep。它允許你快速地在檔案中找到匹配的字串,非常適合與正規表示式一起使用。

範例

假設你有一個日誌檔案,你想要找出所有包含日期格式 "2024-10-08" 的行:

Select-String -Path "C:\logs\mylog.txt" -Pattern "\d{4}-\d{2}-\d{2}"

在這裡,-Pattern 參數用來指定正規表示式模式,Select-String 會在檔案中找出所有符合該模式的行並將其顯示出來。這種方法能夠大大減少你手動尋找的時間,尤其是當檔案非常大時。
你也可以把結果儲存到變數中,並進一步分析:

$errors = Select-String -Path "C:\logs\mylog.txt" -Pattern "Error"
foreach ($error in $errors) {
    Write-Output $error.Line
}

部分書中範例

Get-Childitem -filter *.log -recurse | 
select-string -pattern "\s40[0-9]\s" | 
format-table Filename, lineNumber, Line -wrap

在執行前,先透過下列 script 建立環境

創建一個目錄來存放 log 檔

New-Item -ItemType Directory -Path .\LogFiles -Force

創建多個 .log 文件

Set-Content -Path .\LogFiles\app1.log -Value @"
INFO 2024-10-09 This is a test log entry.
WARN 2024-10-09 This line contains a status code 400.
ERROR 2024-10-09 Error code 401 occurred.
INFO 2024-10-09 Normal operation with status 200.
"@

Set-Content -Path .\LogFiles\app2.log -Value @"
ERROR 2024-10-09 Something bad happened, error code 403.
INFO 2024-10-09 All systems operational.
WARN 2024-10-09 Warning! Status code is 404.
ERROR 2024-10-09 Critical failure at code 405.
"@

Set-Content -Path .\LogFiles\app3.log -Value @"
INFO 2024-10-09 This is a general info log.
ERROR 2024-10-09 Error found with status 500.
WARN 2024-10-09 Status 408 reached a warning level.
INFO 2024-10-09 No issues detected.
"@

執行過程及執行結果

https://ithelp.ithome.com.tw/upload/images/20241009/20168708LIjI3Kb6GD.png
https://ithelp.ithome.com.tw/upload/images/20241009/20168708f7QOU1PUe6.png

逐行解釋

回頭我們再來逐行看其意義,並執行看看結果:

Get-Childitem -filter *.log -recurse | 
select-string -pattern "\s40[0-9]\s" | 
format-table Filename, lineNumber, Line -wrap

第一行

  • Get-ChildItem:用於列出檔案和目錄。
  • -filter \*.log:過濾出 .log 結尾的檔案,這意味著只會選取 log 檔。
  • -recurse:遞迴搜索子目錄,找到所有目錄下的 .log 檔案。

第二行

  • Select-String:在檔案中搜尋匹配指定模式的行,類似於 Linux 中的 grep
  • -pattern "\s40[0-9]\s":這裡的正規表示式解釋如下:
    • \s:代表空白字符(例如空格或 Tab)。
    • 40[0-9]:匹配 400 到 409 之間的任意數字。
    • \s:代表結尾的空白字符。因此這個模式會匹配以空白字符開頭,接著是 "40x"(例如 400、401 等),然後結束於另一個空白字符的部分。

第三行

  • Format-Table:將輸出格式化為表格的形式。
  • FilenameLineNumberLine:顯示匹配行的檔案名、行號和內容。
  • -wrap:將過長的內容換行顯示。

執行結果

https://ithelp.ithome.com.tw/upload/images/20241009/20168708x96Kon8V7f.png


明日主題

Day 26 - Azure DevOps 概覽


上一篇
Day 24 - 改善你的參數化指令
下一篇
Day 26 - Azure DevOps 概覽
系列文
《30天挑戰精通 PowerShell:從 Windows Server 到 Azure DevOps 自動化之旅》30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言