1

我收到一个包含多个列表的文本文件,如下所示(编辑:包括更准确的示例数据集)

# SYSTEM X
# SINGULAR
192.168.1.3
# SUB-SYSTEM V
192.168.1.4
192.168.1.5
192.168.1.6
# SYSTEM Y
# MANDATORY
192.168.1.7
192.168.1.8
192.168.1.9
192.168.1.7
192.168.1.8
192.168.1.9

每个“系统评论”都意味着它之后的一个新集合。我想分别阅读每个内容块,因此应将每个集合分配给丢弃嵌入注释的对象。我只需要IP。就像是:

$ipX = get-content -path [file.txt] [set X]
$ipY = get-content -path [file.txt] [set Y]
$ipZ = get-content -path [file.txt] [set Z]

但我不确定如何实际分别分配这些集合。请帮忙。

4

4 回答 4

1

这是一种可能的解决方案。结果将是一个哈希表,每个键包含该集合的任何 ips 数组:

$result = @{}
get-content file.txt | foreach {
    if ($_ -match "#\s*SET\s+(\w+)") {
        $result[($key = $matches.1)] = @()
    }
    elseif ($_ -notlike "#*") {
        $result[$key] += $_
    }
}

内容$result

Name                           Value                                                                                                                                                                                  
----                           -----                                                                                                                                                                                  
Y                              {[ip], [ip], [more ips]}                                                                                                                                                               
Z                              {[ip], [ip], [more ips]}                                                                                                                                                               
X                              {[ip], [ip], [more ips]}    
于 2020-10-30T15:34:12.997 回答
0

这是另一种方法。我们将利用Foreach-Object'-End块到[PSCustomObject]最后一个。

Get-Content $file | Foreach-Object {
    if($_ -match 'SET (.+?)'){
        if($ht){[PSCustomObject]$ht}
        $ht = [ordered]@{Set = $Matches.1}
    }
    if($_ -match '^[^#]'){
        $ht["IPs"] += $_
    }
} -End {if($ht){[PSCustomObject]$ht}}

输出

Set IPs               
--- ---               
X   [ip][ip][more ips]
Y   [ip][ip][more ips]
Z   [ip][ip][more ips]

如果您还想确保$ht一开始是空的,您可以使用该-Begin块。

Get-Content $file | Foreach-Object -Begin{$ht=$null}{
    if($_ -match 'SET (.+?)'){
        if($ht){[PSCustomObject]$ht}
        $ht = [ordered]@{Set = $Matches.1}
    }
    if($_ -match '^[^#]'){
        $ht["IPs"] += $_
    }
} -End {if($ht){[PSCustomObject]$ht}}
于 2020-10-30T16:04:36.253 回答
0

您可以使用Select-String提取文本的特定部分:

# Update $section to be the set you want to target
$section = 'Set Y'
Get-Content a.txt -Raw |
    Select-String -Pattern "# $section.*\r?\n(?s)(.*?)(?=\r?\n# Set|$)" | Foreach-Object 
        {$_.Matches.Groups[1].Value}

在文件中使用Get-Contentwith-Raw作为单个字符串读取,使多行匹配更容易。PowerShell 7Select-String包含一个-Raw开关,使此过程更简单一些。

这将输出与(.*?). 如果要在注释之间而不是 and 之间捕获Set <something>Set <something>可以-Pattern将末尾的值编辑为 only be#而不是# Set

正则表达式细分:

  • ## 从字面上匹配字符
  • $section替换您的变量值与字面上的值匹配,前提是字符串中没有正则表达式字符
  • .*匹配任何字符(行终止符除外)
  • \r匹配回车
  • ?量词 - 匹配 0 到 1 次,尽可能多次,根据需要回馈(贪婪)
  • \n匹配换行符(换行符)
  • (?s)修饰符:单行。点匹配换行符
  • 第一捕获组(.*?)
  • .*?懒惰地匹配任何字符
  • 积极前瞻(?=\r?\n# Set)
  • \r?匹配回车零次或多次
  • \n匹配换行符(换行符)
  • #Set 匹配# Set字面上的字符
  • $匹配字符串的结尾
于 2020-10-30T16:16:59.697 回答
0

如果我正确理解了新示例的问题,您想要解析文件并创建单个变量,每个变量都包含一个数组 ip IP 地址。

如果是这种情况,您可以这样做:

# loop through the file line-by-line
$result = switch -Regex -File 'D:\Test\thefile.txt' {
    '#\sSYSTEM\s(\w+)' {
        # start a new object, output the earlier object if available
        if ($obj) { $obj }
        $obj = [PsCustomObject]@{ 'System' = $Matches[1]; 'Ip' = @() }
    }
    '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}' {
        # looks like an IPv4 address. Add it to the Ip property array of the object
        $obj.Ip += $_
    }
    default {}
}

现在你在 $result 中有一个数组 ob 对象:

System Ip                                                     
------ --                                                     
Y      {192.168.1.7, 192.168.1.8, 192.168.1.9, 192.168.1.7...}
X      {192.168.1.3, 192.168.1.4, 192.168.1.5, 192.168.1.6}  

制作单独的变量很容易:

$ipX = ($result | Where-Object { $_.System -eq 'X' }).Ip
$ipY = ($result | Where-Object { $_.System -eq 'Y' }).Ip
$ipZ = ($result | Where-Object { $_.System -eq 'Z' }).Ip

您的示例有重复的 IP 地址。如果你不想要这些
$ipX = ($result | Where-Object { $_.System -eq 'X' }).Ip | Select-Object -Unique(其他人也一样)

于 2020-10-31T10:21:15.120 回答