如果-match 返回一个整行,这意味着-match 操作的LHS 是一个数组 em>, 这反过来表明您使用Get-Content 没有-Raw,这会将输入作为行的数组 em>,在这种情况下,-match 充当 过滤器。
相反,将您的文件读取为带有Get-Content -Raw 的单个多行字符串; 带有标量 LHS,
-match然后返回[bool],并且匹配操作的结果报告在自动变量$Matches中(一个哈希表,其0 条目包含整体匹配,1 第一个捕获组匹配的内容,...):
# Read file as a whole, into a single, multi-line string.
$doc = Get-Content -Raw file.txt
if ($doc -match '(?<=hostkey=")(.*)(?=")') {
# Output what the 1st capture group captured
$Matches[1]
}
使用您的示例输入,上述结果
ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
然后您可以扩展该方法以捕获多个令牌,在这种情况下,我建议使用命名捕获组 ((?<name>...));以下示例使用此类命名的捕获组来提取几个感兴趣的标记:
if ($doc -match '(?<=sftp://)(?<username>[^:]+):(?<password>[^@]+)@(?<host>[^:]+)'){
# Output the named capture-group values.
# Note that index notation (['username']) and property
# notation (.username) can be used interchangeably.
$Matches.username
$Matches.password
$Matches.host
}
使用您的示例输入,上述结果:
username
password
host.name.net
您可以扩展上述内容以捕获所有个感兴趣的令牌。
请注意,. 默认不匹配 \n(换行符)字符。
提取许多标记会导致复杂的正则表达式难以阅读,在这种情况下,x (IgnoreWhiteSpace) 正则表达式选项可以提供帮助(作为内联选项,(?x) 在正则表达式):
if ($doc -match '(?x)
(?<=sftp://)(?<username>[^:]+)
:(?<password>[^@]+)
@(?<host>[^:]+)
:(?<port>\d+)
\s+hostkey="(?<sshkey>.+?)"
\n+get\ File\*\.txt\ (?<localpath>.+)
\nmv\ File\*\.txt\ (?<remotepath>.+)
'){
# Output the named capture-group values.
$Matches.GetEnumerator() | ? Key -ne 0
}
注意用于使正则表达式更具可读性(将其分散到多行)的空格在匹配时是如何忽略的,而要在输入中匹配的空格必须转义(例如,匹配单个空格,\ 或 [ ],或 \s 匹配任何空白字符。)
使用您的示例输入,上述结果如下:
Name Value
---- -----
host host.name.net
localpath \local\path\Client\File.txt
port 22
sshkey ssh-rsa 1024 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
remotepath /remote/archive/
password password
username username
请注意,捕获组乱序的原因是$Matches 是一个哈希表(类型为[hashtable]),其键枚举顺序是一个实现工件:没有特定的枚举订单有保障。
但是,对捕获组的随机访问效果很好;例如,$Matches.port 将返回 22。