问题描述
我正在尝试使用 PowerShell 解析 SFTP 配置文件 (sshd_config.txt) 以获取所有现有的 SFTP 配置文件。下面的文本只是 3 个配置文件,但可能有数百个我需要解析。一旦我有一个有效的正则表达式将所有匹配项输出到 PowerShell 对象,我就可以解析各个配置文件了。我只是不知道如何编写正则表达式。我确实尝试使用其他示例,但我无法将每个示例分成单独的匹配项。
我需要匹配开始“^Match”和所有行直到一个空行。任何帮助将不胜感激。
Match User thedomain\user1
ChrootDirectory E:\sftp\heatism\user1
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
Match User thedomain\user2
ChrootDirectory E:\sftp\heatism\user2
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
Match User thedomain\user3
ChrootDirectory E:\sftp\heatism\user3
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
解决方法
跨多行匹配:
-
您需要一个单行多行字符串作为输入,这就是
Get-Content
的-Raw
开关提供的(默认情况下,Get-Content
输出输入文件的行 一一). -
-
Multiline
(m
),为了使^
和$
匹配单行的开头和结尾多行字符串;\A
和\Z
(或\z
,仅匹配字符串的末尾,即使它是换行符)然后可用于匹配多个的整体开头和结尾-line 字符串。 -
Singleline
(s
) 如果您希望.
也匹配 换行符 字符 (\n
)。 -
指定这些选项的最简单方法是在正则表达式开头的
(?...)
内;在手头的情况下:(?ms)
-
总而言之,使用 Jan's helpful regex 的修改版本和 .NET System.Text.RegularExpressions.Regex.Matches()
方法来查找给定正则表达式的 all 匹配项(注意 PowerShell 的 {{ 3}} 只查找 first):
foreach ($m in [regex]::Matches(
(Get-Content -Raw sshd_config.txt),'(?ms)^Match User .+?(?=^$|\Z)'
)) {
# Split the block of line into the first and the remaining lines.
$first,$rest = $m.Value.Trim() -split '\r?\n'
# Create an aux. (ordered) hashtable and fill it with the user name
# extracted from the first line.
$oht = [ordered] @{ UserName = (-split $first)[-1] }
# Loop over the remaining lines,split them into name and value,# and add them to the hashtable.
foreach ($line in $rest) {
$name,$value = $line.Trim() -split ' ',2
$oht[$name] = $value
}
# Convert the hashtable to a custom object and output it.
[pscustomobject] $oht
}
通过您的示例输入,您将看到以下输出,代表所创建的 [pscustomobject]
实例的默认格式:
UserName : thedomain\user1
ChrootDirectory : E:\sftp\heatism\user1
PermitTunnel : no
AllowAgentForwarding : no
AllowTcpForwarding : no
X11Forwarding : no
ForceCommand : internal-sftp
UserName : thedomain\user2
ChrootDirectory : E:\sftp\heatism\user2
PermitTunnel : no
AllowAgentForwarding : no
AllowTcpForwarding : no
X11Forwarding : no
ForceCommand : internal-sftp
UserName : thedomain\user3
ChrootDirectory : E:\sftp\heatism\user3
PermitTunnel : no
AllowAgentForwarding : no
AllowTcpForwarding : no
X11Forwarding : no
ForceCommand : internal-sftp
,
您可以使用(感谢 @mklement0 的一些改进):
(?m)^Match[\s\S]+?(?=^$|\Z)
查看 a demo on regex101.com 并注意 multiline
标志。
说明:
^Match # match "Match" at the very beginning of a line
[\s\S]*? # match anything else lazily
(?=^$|\Z) # make sure what follows is a blank line or the very end of the string
,
另一种选择是以 Match
开始模式,然后是该行的其余部分。然后继续使用负前瞻匹配所有非空行。
^Match .*(?:\r?\n(?!$).*)*
模式匹配:
^Match
-
.*
匹配该行的其余部分 -
(?:
非捕获组-
\r?\n(?!$)
匹配换行符并断言该行不为空 -
.*
匹配该行的其余部分
-
-
)*
关闭非捕获组并可选择重复
看到一个 regex demo。
如果您也不想匹配仅包含空格的行:
^Match .*(?:\r?\n(?![\p{Zs}\t]*$).*)*
示例
$allText = Get-Content -Raw sshd_config.txt
$pattern = "(?m)^Match .*(?:\r?\n(?![\p{Zs}\t]*$).*)*"
Select-String $pattern -input $allText -AllMatches | Foreach-Object {$_.Matches} | Foreach-Object {
$_.Value
"--------------------------"
}
输出
Match User thedomain\user1
ChrootDirectory E:\sftp\heatism\user1
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
--------------------------
Match User thedomain\user2
ChrootDirectory E:\sftp\heatism\user2
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
--------------------------
Match User thedomain\user3
ChrootDirectory E:\sftp\heatism\user3
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
ForceCommand internal-sftp
--------------------------