将PowerShell空格分隔的输出解析为表

时间:2018-07-05 21:19:09

标签: powershell

PowerShell在运行命令时将输出返回给我:

PS Output

Mod  Ports  Module-Type                         Model              Status
---  -----  -----------                         ------------------ ----------
1    48     2/4/8/10/16 Gbps Advanced FC Module DS-X9448-768K9     ok
2    48     2/4/8/10/16 Gbps Advanced FC Module DS-X9448-768K9     ok
3    0      Supervisor Module-3                 DS-X97-SF1-K9      ha-standby
4    0      Supervisor Module-3                 DS-X97-SF1-K9      active *

我在尝试拆分时遇到了麻烦,因为它不是制表符分隔的,而是空格分隔的,因此,当我使用.split("")时,列Module-Type的分隔不正确是因为它的内容也有空格。

我是新来的,任何帮助将不胜感激。

这是我的代码:

$RS = .\Plink server@puttysession -pw "password" "command"

foreach ($RSln in $RS){
    $arr = $RSln.split('',[System.StringSplitOptions]::RemoveEmptyEntries)
    Write-Host $RSln "|" $arr.Length
}

这给了我创建的数组的行和长度,前两行是长度为5的数组,由于ModuleType

中的第三行和第四行有9项

2 个答案:

答案 0 :(得分:2)

在PowerShell中处理此类输入的推荐方法是将其解析为自定义对象。您可以使用正则表达式来做到这一点:

$RS | Where-Object {
    $_ -match '(\d+)\s+(\d+)\s+(.*?)\s+([a-z]+(?:-[a-z0-9]+){2,})\s+(.*)'
} | ForEach-Object {
    New-Object -Type PSObject -Property @{
        'Mod'        = [int]$matches[1]
        'Ports'      = [int]$matches[2]
        'ModuleType' = $matches[3]
        'Model'      = $matches[4]
        'Status'     = $matches[5]
    }
}

或(如果列的宽度是固定的,则)通过以定义的偏移量提取子字符串来实现:

$RS | Select-Object -Skip 2 | ForEach-Object {
    New-Object -Type PSObject -Property @{
        'Mod'        = [int]$_.Substring(0, 3).Trim()
        'Ports'      = [int]$_.Substring(5, 5).Trim()
        'ModuleType' = $_.Substring(12, 35).Trim()
        'Model'      = $_.Substring(48, 18).Trim()
        'Status'     = $_.Substring(67).Trim()
    }
}

需要Select-Object -Skip 2来跳过2个标题行。

如果所有列都被一个以上的空格分隔,则可以通过-split '\s\s+'分隔(以2个或更多连续的空白字符分隔)。但是,对于您的数据则不是这样,因为至少前2个数据行在第3列和第4列之间只有一个空格。

答案 1 :(得分:0)

大多数PowerShell脚本编写者可能会说,将类似于Format-Table输出的任何文本表用作输入是个坏主意,但我想挑战一下,因为格式化后的源表可以被人类读取,如果人类可以读取可以阅读并确定关于列的开始和结束位置的布局,程序应该能够执行相同的操作...

在某些情况下(例如,对于StackOverflow网站上的示例数据),它甚至可能比其他格式(如CSV难以读取且仅支持字符串数据< / em>),XML非常冗长,因此也难以阅读)或JSON(或PSON复杂数据,但不适用于包含简单本机属性的对象列表

基于这种想法,我编写了一个可重用的ConvertFrom-SourceTable cmdlet,可以从PowerShell画廊下载该文件,并从GitHub iRon7/ConvertFrom-SourceTable存储库中获取源代码。

在您的情况下,将表转换为对象的命令就像$RS | ConvertFrom-SourceTable一样简单,让我展示一下:

$RS = '
    Mod Ports Module-Type                        Model              Status
    --- ----- ---------------------------------- ------------------ -----------
    1   48    2/4/8/10/16 Gbps Advance FC Module DS-X9448-768K9     ok
    2   48    2/4/8/10/16 Gbps Advance FC Module DS-X9448-768K9     ok
    3   0     Supervisor Module-3                DS-X97-SF1-K9      ha-standby
    4   0     Supervisor Module-3                DS-X97-SF1-K9      active *
'

$RS | ConvertFrom-SourceTable

Status      : ok
Model       : DS-X9448-768K9
Ports       : 48
Mod         : 1
Module-Type : 2/4/8/10/16 Gbps Advance FC Module

Mod         : 2
Module-Type : 2/4/8/10/16 Gbps Advance FC Module
Ports       : 48
Model       : DS-X9448-768K9
Status      : ok

Mod         : 3
Module-Type : Supervisor Module-3
Ports       : 0
Model       : DS-X97-SF1-K9
Status      : ha-standby

Mod         : 4
Module-Type : Supervisor Module-3
Ports       : 0
Model       : DS-X97-SF1-K9
Status      : active *

由于所有数据都保持左对齐(并且每一列都需要一个标题),因此可以从一开始就确定列的布局,这意味着您甚至可以 stream 该表输入(假设{ {1}}通过管道分别输出每行):

.\Plink

(意思是如果您将源表提供为多行字符串,则.\Plink server@puttysession -pw "password" "command" | ConvertFrom-SourceTable cmdlet将确定整个表上的列,否则将基于标题,过去和当前记录)

如果源表具有更好的格式约定,例如“非字符串数据(需要解释的数据)右对齐”(实际上由ConvertFrom-SourceTable完成)。您可以假设(如@Ansgar Wiechers所做的那样)Format-TableMod是整数是事实。例如:

Ports

(请注意,在此示例中,$Object = ConvertFrom-SourceTable ' Mod Ports Module-Type Model Status --- ----- ----------- ----- ------ 1 48 2/4/8/10/16 Gbps Advance FC Module DS-X9448-768K9 ok 2 48 2/4/8/10/16 Gbps Advance FC Module DS-X9448-768K9 ok 3 0 Supervisor Module-3 DS-X97-SF1-K9 ha-standby 4 0 Supervisor Module-3 DS-X97-SF1-K9 ha-standby ' 将提供与输入相同的输出)

有关更多示例,请使用帮助:$Object | Format-Table