【问题标题】:Handling Data & Sorting Results in PowerShell在 PowerShell 中处理数据和排序结果
【发布时间】:2022-01-01 03:39:37
【问题描述】:

我在处理从 PowerShell 查询返回的数据时遇到问题。

我的目标是获取所有超过 30 天 (>30d) 的 NAME。

之后,我想将这些结果的名称加载到一个数组中。

我的查询返回的数据如下:

PS C:\Users\> $output
NAME                      STATUS   AGE
dread-gorge               Active   284d
dread-lagoon              Active   210d
carncier-basin            Active   164d
chantague-shallows        Active   164d
hilraine-loch             Active   311d
stangrave-waters          Active   271d

运行“选择对象”或“排序对象”来过滤输出不起作用。

$output | Select-Object -Property NAME
$output | Sort-Object NAME

【问题讨论】:

  • 看起来$output 包含一个或多个字符串,而不是结构化对象。您最初是如何获得这些数据的?
  • 这是我在 Powershell 中运行的 kubectl 查询的输出。所以,它的原始格式是 JSON。
  • 在这种情况下,您可能希望使用--output=json 运行查询并将其通过管道传输到ConvertFrom-Json
  • 你可以做类似@($output -split '\r?\n' |Select -Skip 1 |ForEach-Object Trim) -replace '\s.+$'
  • 如果输出确实是空格分隔的数据,您可以跳过输出的第一行(列名)并使用正则表达式来获取每行的第一个标记。但是(正如 Mathias 指出的那样)如果可能的话,最好将其解析为 json 数据(更精确、更直接、更不容易出错)。

标签: powershell kubectl text-parsing


【解决方案1】:

如果$output单个多行字符串,您可以这样做:

$result = ($output -split '\r?\n' -replace '\s+', ',' | ConvertFrom-Csv | Where-Object {[int]($_.Age -replace '\D') -gt 30}).NAME

获取数组中的名称$result

如果$output 已经是一个字符串数组,那么:

$result = ($output -replace '\s+', ',' | ConvertFrom-Csv | Where-Object {[int]($_.Age -replace '\D') -gt 30}).NAME

【讨论】:

    【解决方案2】:

    更新:

    • 有关将输入转换为 CSV 格式并使用ConvertFrom-Csv 对其进行解析的卓越解决方案,请参阅Theo's answer

    • 下面的解决方案可能对其文本解析技术感兴趣。


    正如 cmets 所说,通常最好让外部程序发出 结构化 文本,例如 JSON,因为解析用于显示的格式化文本本质上是脆弱的。
    根据kubectl docs,您可以使用-o json 来实现这一点(正如Mathias 也指出的那样)。

    如果数据足够简单以至于纯文本解析仍然是一种选择,您可以尝试以下方法,它依赖于 -split operator 的一元形式将每一行分成字段:

    # Sample output from kubectl.
    # Note: Capturing output from an external programs such as kubectl
    #       results in an *array of lines*.
    #       The -split '\r?\n` operation splits the multiline here-string into
    #       just that.
    $kubeCtlOutput = @'
    NAME                      STATUS   AGE
    dread-gorge               Active   28d
    dread-lagoon              Active   31d
    carncier-basin            Active   16d
    chantague-shallows        Active   164d
    '@ -split '\r?\n'
    
    # Process the array's lines.
    [array] $namesOfInterest = 
      $kubeCtlOutput | 
        Select-Object -Skip 1 |
          ForEach-Object { 
            $name, $age = (-split $_)[0, -1]
            if ([int] ($age -replace '\D') -gt 30) {
              $name
            }
          }
    
    $namesOfInterest # Print the result.
    

    输出,显示只提取了AGE大于30天数的两行名称:

    dread-lagoon
    chantague-shallows
    

    This related question 的答案定义了通用帮助函数,这些函数可以将列式纯文本数据解析为对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-28
      • 1970-01-01
      • 2012-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多