第24章学习笔记|用正则表达式解析文本文件(PowerShell 实战)
第24章学习笔记|用正则表达式解析文本文件(PowerShell 实战)
目标:会写/读常用正则,知道在 PowerShell 里该用哪种工具(
-match
、Select-String
),搞定日志文本解析。
TL;DR
-
何时用正则:当输入是“纯文本”而不是对象(如 IIS/应用日志、WindowsUpdate.log 等)。
-
两大利器:
"-match"
:判断与提取(走内存字符串,支持$matches
)。Select-String
:在文件/流里搜索,返回MatchInfo
(含文件名、行号、匹配行)。
-
PowerShell默认不区分大小写;区分时用
-cmatch
。 -
写正则时用单引号,避免字符串插值和转义地狱;需要变量插入再用双引号。
-
尽量对象化;只有文本不可避免时再上正则。
1)正则速览(够用版)
常用“字符类/锚点/量词”:
- 字符类
\w
字母数字下划线;\W
非\w
\d
数字;\D
非数字
\s
空白;\S
非空白
.
任意单字符
[abc]
集合;[^abc]
非集合
[a-z]
范围;可并列:[a-fm-z]
- 量词
?
0或1次;*
0到多次;+
1到多次;{n}
恰好n;{n,}
至少n;{n,m}
n到m - 锚点
^
行首;$
行尾 - 转义
\.
匹配句号;\\
匹配反斜杠
示例模式(可直接用):
- IPv4(宽松校验):
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
- UNC 路径:
\\\\\w+(\\\w+)+
- 公司邮箱(示例):
\w\.\w+@company\.com
- IIS 40x:
\s40[0-9]\s
2)-match
与 $matches
:判断 + 提取
"don" -match 'd[aeiou]n' # True
"dooon" -match 'd[aeiou]+n' # True
"docon" -match 'd[aeiou]n' # False
带捕获分组:
$line = 'ip=192.168.1.10 user=bob'
if ($line -match 'ip=(\d{1,3}(?:\.\d{1,3}){3})\s+user=(\w+)') {$ip = $matches[1]$user = $matches[2]
}
区分大小写用
-cmatch
;不匹配用-notmatch
。
3)Select-String
:在文件/流中找
在日志树中找所有 40x:
Get-ChildItem -Recurse -Filter *.log |Select-String -Pattern '\s40[0-9]\s' |Format-Table Filename, LineNumber, Line -Wrap
查找特定 User-Agent(Windows NT 6.2 + Gecko):
Get-ChildItem -Recurse -Filter *.log |Select-String -Pattern '6\.2;[\w\W]+\+Gecko'
结合事件日志(两种思路):
-
先取
Message
文本再匹配(输出匹配文本):Get-EventLog -LogName Security |Where-Object EventId -eq 4624 |Select-Object -ExpandProperty Message |Select-String -Pattern 'WIN[\w\W]+TM[234][0-9]\$'
-
直接在对象层过滤(输出事件对象):
Get-EventLog -LogName Security |Where-Object { $_.EventId -eq 4624 -and $_.Message -match 'WIN[\w\W]+TM[234][0-9]\$' }
小技巧:
- 返回所有匹配用
-AllMatches
,上下文用-Context 2,2
。 - 超大文件优先
Get-Content -ReadCount 1000
分批管道,或.NET
流式读取。
4)IIS/文本日志常见任务模板
A. 抓缺失文件(40x)
Get-ChildItem -Recurse -Filter *.log |Select-String '\s40[0-9]\s' |ForEach-Object {[PSCustomObject]@{File = $_.PathLine = $_.LineNumberText = $_.Line}} | Export-Csv .\404_499.csv -NoTypeInformation
B. 提取 IPv4 出来入表
Get-ChildItem -Recurse -Filter *.log |Select-String -Pattern '\b(\d{1,3}(?:\.\d{1,3}){3})\b' -AllMatches |ForEach-Object {foreach ($m in $_.Matches) {[PSCustomObject]@{ File=$_.Path; Line=$_.LineNumber; IP=$m.Groups[1].Value }}} | Sort-Object IP -Unique
5)实战练习(参考答案思路)
1)名称含两位数字的文件:
Get-ChildItem C:\Windows | Where-Object { $_.Name -match '\d{2}' }
2)微软公司进程(显示 Name、Id、Company):
Get-Process |Where-Object { $_.Company -match '^Microsoft' } |Select-Object Name, Id, Company
3)WindowsUpdate.log 中“代理开始安装”行(示例关键字,视版本变动):
Get-Content C:\Windows\WindowsUpdate.log |Select-String 'Start[\w\W]+Agent: Installing Updates'
4)Get-DnsClientCache
仅显示 Data 为 IPv4:
Get-DnsClientCache | Where-Object {$_.Data -match '^\d{1,3}(\.\d{1,3}){3}$'
}
6)易错与优化
- 引号:写模式优先单引号;需要变量插值才用双引号(注意转义
\
与 PowerShell 自身的`
)。 - 大小写:默认不区分,用
-cmatch
才区分。 - 贪婪/最短:
+
/*
默认贪婪,最短匹配用+?/*?
(.NET 正则支持)。 - 性能:超大文本尽量管道流式,需要全局统计时再收集;避免一次性
-Raw
读入超大文件。 - 能对象化就对象化:日志若有结构化替代(CIM、EventLog API、专用解析器),优先不用正则。
7)继续学习
help about_Regular_Expressions
(PowerShell 内置说明)Select-String -AllMatches/-Context
、-NotMatch
、-cmatch
、$matches
- 高级脚本参数验证:
[ValidatePattern()]
- 在线库/调试器:RegExLib、正则测试网站(离线亦可用 VSCode 的「.*」查找测试)
心法:先把问题对象化;不得不文本解析时,先写能工作的小正则,再逐步加锚点/分组/量词,边测边收敛。