我有一个烦人的报告输出(诅咒是惠普),这不是我可以通过查询形成的东西 - 它或多或少都是或多或少。我想从每个" chunk"中取两行。输出并从中构造一个数组。我认为这将是一个简单的split()操作,但没有这样的运气。输出的样本如下:
Medium identifier : 1800010a:54bceddd:1d8c:0007
Medium label : [ARJ170L6] ARJ170L6
Location : [TapeLibrary: 24]
Medium Owner : wfukut01
Status : Poor
Blocks used [KB] : 2827596544
Blocks total [KB] : 2827596544
Usable space [KB] : 1024
Number of writes : 16
Number of overwrites : 4
Number of errors : 0
Medium initialized : 19 January 2015, 11:43:32
Last write : 26 April 2016, 21:02:12
Last access : 26 April 2016, 21:02:12
Last overwrite : 24 April 2016, 04:48:55
Protected : Permanent
Write-protected : No
Medium identifier : 1800010a:550aa81e:3a0c:0006
Medium label : [ARJ214L6] ARJ214L6
Location : External
Medium Owner : wfukut01
Status : Poor
Blocks used [KB] : 2904963584
Blocks total [KB] : 2904963584
Usable space [KB] : 0
Number of writes : 9
Number of overwrites : 7
Number of errors : 0
Medium initialized : 19 March 2015, 10:42:45
Last write : 30 April 2016, 22:14:19
Last access : 30 April 2016, 22:14:19
Last overwrite : 29 April 2016, 13:41:35
Protected : Permanent
Write-protected : No
如果这项工作的最终输出会创建一个与此类似的数组,那么理想的是:
Location UsableSpace
--------- -------------
External 0
TapeLibrary 1024
所以我可以(例如)查询输出,以便我可以对数组中的数据进行操作:
$myvar | where-object { $_.Location -eq "TapeLibrary" }
也许有更好的方法?我很乐意听到他们的声音!
答案 0 :(得分:2)
最简单的方法是使用命令本身和select
某些属性。如果该命令是powershell cmdlet,则应返回对象。
$output = Some-HPCommand | select 'Medium label', 'Location'
然后您可以访问特定属性:
$output.'Medium label'
$output.Location
如果您可以提供完全命令,我可以更准确地写出来。
人们学习PowerShell时最大的问题是他们将输出视为 String ...... PowerShell中的所有内容都是面向对象的,一旦你开始考虑 Objects < / em>,处理数据变得更加容易;换句话说,总是尝试将输出作为对象或对象数组来处理。它会让你的生活变得更加容易。
答案 1 :(得分:2)
如果该命令不是像Kolob Canyon的答案那样的Powershell cmdlet,那么您需要解析文本。这是使用-match
和正则表达式找到Location
和Usable space [KB]
的行并在冒号后面找到单词字符的不典型示例。
((Get-Content C:\Example.txt -Raw) -split 'Medium identifier') | ForEach-Object {
[void]($_ -match 'Location\s+:\s(.*?(\w+).*)\r')
$Location = @($Matches.values | Where-Object {$_ -notmatch '\W'})[0]
[void]($_ -match 'Usable\sspace\s\[KB\]\s+:\s(.*?(\w+).*)\r')
$UsableSpace = @($Matches.values | Where-Object {$_ -notmatch '\W'})[0]
if ($Location -or $UsableSpace){
[PSCustomObject]@{
Location = $Location
UsableSpace = $UsableSpace
}
}
}
由于这是非常脆弱和不优雅的,所以尽可能与对象进行交互要好得多。
答案 2 :(得分:2)
假设数据与它看起来一样规则,您可以使用多个赋值从数组中提取数据,如下所示:
$data = 1, 2, "ignore me", 3, 10, 22, "ignore", 30
$first, $second, $null, $third, $data = $data
第一个,第二个和第四个数组元素进入变量,“忽略我”在$null
中被丢弃,剩下的数据返回到数据中。在您的情况下,这看起来像:
# Read the file into an array
$data = Get-Content data.txt
# Utility to fix up the data row
function FixUp ($s)
{
($s -split ' : ')[1].Trim()
}
# Loop until all of the data is processed
while ($data)
{
# Extract the current record using multiple assignment
# $null is used to eat the blank lines
$identifier,$null,$label,$location,$owner,$status,
$used,$total,$space,$writes,$overwrites,
$errors, $initialized, $lastwrite, $lastaccess,
$lastOverwrite, $protected, $writeprotected,
$null, $null, $data = $data
# Convert it into a custom object
[PSCustomObject] [ordered] @{
Identifier = fixup $identifier
Label = fixup $label
location = fixup $location
Owner = fixup $owner
Status = fixup $status
Used = fixup $used
Total = fixup $total
Space = fixup $space
Write = fixup $writes
OverWrites = fixup $overwrites
Errors = fixup $errors
Initialized = fixup $initialized
LastWrite = [datetime] (fixup $lastwrite)
LastAccess = [datetime] (fixup $lastaccess)
LastOverWrite = [datetime] (fixup $lastOverwrite)
Protected = fixup $protected
WriteProtected = fixup $writeprotected
}
}
提取数据后,您可以按照自己想要的方式对其进行格式化
答案 3 :(得分:2)
这看起来非常规律,所以我说有三种典型方法。
首先:你自己的bucket-fill-trigger-empty解析器,加载线直到你到达下一个触发器(&#34; Medium标识符&#34;),然后将桶清空到管道并开始一个新的
类似的东西:
$bucket = @{}
foreach ($line in Get-Content -LiteralPath C:\path\data.txt)
{
# if full, empty bucket to pipeline
if ($line -match '^Medium identifier')
{
[PSCustomObject]$bucket
$bucket = @{}
}
# add line to bucket (unless it's blank)
if (-not [string]::IsNullOrWhiteSpace($line))
{
$left, $right = $line.Split(':', 2)
$bucket[$left.Trim()] = $right.Trim()
}
}
# empty last item to pipeline
[PSCustomObject]$bucket
根据品味识别数字,日期等进行调整
第二:多线正则表达式:我试过,但不能。它看起来像是:
# Not working, but for example:
$r = @'
Medium identifier : (?<MediumIdentifier>.*)
\s*
Write-protected : (?<WriteProtected>.*)
Blocks used [KB] : (?<BlockesUsed>.*)
Medium label : (?<MediumLabel>.*)
Last write : (?<LastWrite>.*)
Medium Owner : (?<MediumOwner>.*)
Usable space [KB] : (?<UsableSpaceKB>.*)
Number of overwrites : (?<NumberOfOverwrites>.*)
Last overwrite : (?<LastOverwrite>.*)
Medium identifier : (?<MediumIdentifier>.*)
Blocks total [KB] : (?<BlocksTotalKB>.*)
Number of errors : (?<NumberOfErrors>.*)
Medium initialized : (?<MediumInitialized>.*)
Status : (?<Status>.*)
Location : (?<Location>.*)
Protected : (?<Protected>.*)
Number of writes : (?<NumberOfWrites>.*)
Last access : (?<LastAccess>.*)
\s*
'@
[regex]::Matches((get-content C:\work\a.txt -Raw), $r,
[System.Text.RegularExpressions.RegexOptions]::IgnoreCase +
[System.Text.RegularExpressions.RegexOptions]::Singleline
)
第三:ConvertFrom-String
- http://www.lazywinadmin.com/2014/09/powershell-convertfrom-string-and.html或https://blogs.technet.microsoft.com/ashleymcglone/2016/09/14/use-the-new-powershell-cmdlet-convertfrom-string-to-parse-klist-kerberos-ticket-output/然后制作模板后
Get-Content data.txt | ConvertFrom-String -TemplateFile .\template.txt
答案 4 :(得分:1)
如果每个部分的格式相同,即可用空间部分总是从该位置向下5行,那么您可以将Select-String
与context参数结合使用。像这样:
Select-String .\your_file.txt -Pattern '(?<=Location\s*:\s).*' -Context 0, 5 | % {
New-Object psobject -Property @{
Location = (($_.Matches[0] -replace '\[|\]', '') -split ':')[0]
UsableSpace = ($_.Context.PostContext[4] -replace '^\D+(\d+)$', '$1' )
}
}