Powershell Get-Content 文本中的特定内容
Powershell Get-Content specific content inside text
我收到一个包含多个列表的文本文件,如下所示(编辑:包括更准确的示例数据集)
# 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
每个“SYSTEM 注释”都意味着它后面的一组新注释。
我想分别阅读每个内容块,因此应将每组内容分配给一个丢弃嵌入评论的对象。我只需要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]
但我不确定如何实际分别分配这些集合。
请帮忙
这是一种可能的解决方案。结果将是一个哈希表,每个键包含该集合的任何 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]}
这是另一种方法。我们将利用 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}}
您可以使用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-Content
和 -Raw
将文件作为单个字符串读入,使 multi-line 匹配更容易。在 PowerShell 7 中,Select-String
包含一个 -Raw
开关,使此过程稍微简单一些。
这会输出匹配 (.*?)
的捕获组 1 结果。如果你想在评论之间而不是在 Set <something>
和 Set <something>
之间进行捕获,你可以将最后的 -Pattern
值编辑为 #
而不是 # Set
.
正则表达式分解:
#
按字面意思匹配字符 #
$section
替换您的变量值与字面上的值匹配,前提是字符串中没有正则表达式字符
.*
匹配任何字符(行终止符除外)
\r
匹配一个回车 return
?
量词——匹配0到1次,次数为
可能,根据需要回馈(贪婪)
\n
匹配 line-feed(换行)字符
(?s)
修饰符:单行。点匹配换行符
- 第 1 个捕获组
(.*?)
.*?
延迟匹配任何字符
- 正前瞻
(?=\r?\n# Set)
\r?
匹配回车 return 零次或多次
\n
匹配 line-feed(换行)字符
#
设置匹配字符 # Set
字面意思
$
匹配字符串结尾
如果我正确理解了新示例的问题,您想解析文件并创建单个变量,每个变量都包含一个数组 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 中有一个对象数组:
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
(其他同理)
我收到一个包含多个列表的文本文件,如下所示(编辑:包括更准确的示例数据集)
# 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
每个“SYSTEM 注释”都意味着它后面的一组新注释。 我想分别阅读每个内容块,因此应将每组内容分配给一个丢弃嵌入评论的对象。我只需要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]
但我不确定如何实际分别分配这些集合。 请帮忙
这是一种可能的解决方案。结果将是一个哈希表,每个键包含该集合的任何 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]}
这是另一种方法。我们将利用 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}}
您可以使用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-Content
和 -Raw
将文件作为单个字符串读入,使 multi-line 匹配更容易。在 PowerShell 7 中,Select-String
包含一个 -Raw
开关,使此过程稍微简单一些。
这会输出匹配 (.*?)
的捕获组 1 结果。如果你想在评论之间而不是在 Set <something>
和 Set <something>
之间进行捕获,你可以将最后的 -Pattern
值编辑为 #
而不是 # Set
.
正则表达式分解:
#
按字面意思匹配字符#
$section
替换您的变量值与字面上的值匹配,前提是字符串中没有正则表达式字符.*
匹配任何字符(行终止符除外)\r
匹配一个回车 return?
量词——匹配0到1次,次数为 可能,根据需要回馈(贪婪)\n
匹配 line-feed(换行)字符(?s)
修饰符:单行。点匹配换行符- 第 1 个捕获组
(.*?)
.*?
延迟匹配任何字符- 正前瞻
(?=\r?\n# Set)
\r?
匹配回车 return 零次或多次\n
匹配 line-feed(换行)字符#
设置匹配字符# Set
字面意思$
匹配字符串结尾
如果我正确理解了新示例的问题,您想解析文件并创建单个变量,每个变量都包含一个数组 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 中有一个对象数组:
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
(其他同理)