使用 Powershell 和 Regex 从文本文件中提取行块
Use Powershell and Regex to extract block of lines from a text file
我正在开发 Powershell 脚本和 .Net Regex,以使用 powershell 和 regex 在网络设备配置中查找模式匹配。我在尝试从配置文件中提取一段字符串时遇到问题,并且在编写正则表达式语句以匹配回车 return 和新行时遇到问题。下面是我的例子。我有一个配置文件,其中包含我要提取的信息
vlan no description ports
999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9
Gi1/0, Gi1/11, Gi1/12, Gi1/13, Gi1/14, Gi1/15, Gi1/16
Gi1/17, Gi1/18
这是我的代码
$File = Get-content C:\config.txt
$Regex = "(?sm)(^999.*(\r\n\s+.*)"
$unused_ports = Select-String -path $File -Pattern $Regex
Write-host $Unused_ports
只显示第一行
999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9
我也尝试了下面的 $Regex
$Regex = '(?m)(^999.*\s+Gi1/10.*)
$Regex = '(?m)(^999.*\r\n\s+Gi1/10.*)
但是 none 我使用的正则表达式提取了所有端口(3 行)
我也使用了 get-content c:\config.txt -raw
但这会显示配置文件中的所有内容。
如果有人可以帮助提取所有三行端口号以及如何使用回车 return 和换行来匹配新行,我将不胜感激。
Wiktor Stribiżew 在对问题的评论中提供了关键指针[1]
: 您必须使用 Get-Content -Raw
将文件内容读入 单个 字符串,以便您的正则表达式可以匹配 跨行 :
if ((Get-Content -Raw C:\Config.txt) -match '(?ms)^999.*?(?=\r?\n\S|\Z)') {
$Matches[0] # automatic variable $Matches reflects what was captured
}
正则表达式也需要一些调整,包括使用 non-greedy 量词 .*?
,如 TheMadTechnician 所建议:
(?ms)
设置正则表达式选项 m
(将 ^
和 $
视为 line 锚点)和 s
(使 .
也匹配 \n
(换行符)`。
^999.*?
匹配以 999
开头的任何行以及任何后续字符 non-greedily.
(?=\r?\n\S|\Z)
是正 look-ahead 断言 ((?=...)
) 匹配换行符 (\r?\n
) 后跟一个 non-whitespace 字符 (\S
) - 假设是 next 块的开始 - 或者 (|
)输入的结尾 (\Z
) - 实际上,这匹配文件的结尾或下一个块的开头,但不将其包含在 $Matches
.[=32 中记录的匹配中=]
[1] Wiktor 还建议正则表达式 (?m)^999.*(?:\r?\n.*){2}
,它适用于示例输入,但仅限于恰好有 3 行的块 - 相比之下,此处提供的解决方案发现任何长度的块,只要 non-initial 块行都具有前导空格。
我正在开发 Powershell 脚本和 .Net Regex,以使用 powershell 和 regex 在网络设备配置中查找模式匹配。我在尝试从配置文件中提取一段字符串时遇到问题,并且在编写正则表达式语句以匹配回车 return 和新行时遇到问题。下面是我的例子。我有一个配置文件,其中包含我要提取的信息
vlan no description ports 999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9 Gi1/0, Gi1/11, Gi1/12, Gi1/13, Gi1/14, Gi1/15, Gi1/16 Gi1/17, Gi1/18
这是我的代码
$File = Get-content C:\config.txt
$Regex = "(?sm)(^999.*(\r\n\s+.*)"
$unused_ports = Select-String -path $File -Pattern $Regex
Write-host $Unused_ports
只显示第一行
999 unused Gi1/2,Gi1/3, Gi1/4, Gi1/5, Gi1/6, Gi/7, Gi/8, Gi1/9
我也尝试了下面的 $Regex
$Regex = '(?m)(^999.*\s+Gi1/10.*)
$Regex = '(?m)(^999.*\r\n\s+Gi1/10.*)
但是 none 我使用的正则表达式提取了所有端口(3 行)
我也使用了 get-content c:\config.txt -raw
但这会显示配置文件中的所有内容。
如果有人可以帮助提取所有三行端口号以及如何使用回车 return 和换行来匹配新行,我将不胜感激。
Wiktor Stribiżew 在对问题的评论中提供了关键指针[1]
: 您必须使用 Get-Content -Raw
将文件内容读入 单个 字符串,以便您的正则表达式可以匹配 跨行 :
if ((Get-Content -Raw C:\Config.txt) -match '(?ms)^999.*?(?=\r?\n\S|\Z)') {
$Matches[0] # automatic variable $Matches reflects what was captured
}
正则表达式也需要一些调整,包括使用 non-greedy 量词 .*?
,如 TheMadTechnician 所建议:
(?ms)
设置正则表达式选项m
(将^
和$
视为 line 锚点)和s
(使.
也匹配\n
(换行符)`。^999.*?
匹配以999
开头的任何行以及任何后续字符 non-greedily.(?=\r?\n\S|\Z)
是正 look-ahead 断言 ((?=...)
) 匹配换行符 (\r?\n
) 后跟一个 non-whitespace 字符 (\S
) - 假设是 next 块的开始 - 或者 (|
)输入的结尾 (\Z
) - 实际上,这匹配文件的结尾或下一个块的开头,但不将其包含在$Matches
.[=32 中记录的匹配中=]
[1] Wiktor 还建议正则表达式 (?m)^999.*(?:\r?\n.*){2}
,它适用于示例输入,但仅限于恰好有 3 行的块 - 相比之下,此处提供的解决方案发现任何长度的块,只要 non-initial 块行都具有前导空格。