如何过滤从控制台程序中获取的 powershell 中的行?

How to filter rows in the powershell which are taken from console program?

我有一个 .exe 控制台程序,它以下列格式将结果放入控制台:

 ------------------ ----------- ----------------
  CompanyName        CompanyId   CompanyType
 ------------------ ----------- ----------------
  test1              1           Root
  test2              2           Center
  test3              3           Company
 ------------------ ----------- ----------------

我想在 PowerShell 脚本中获取它并按 CompanyName.

过滤

我试过:

MyTool.exe companies | where {$_.CompanyName -eq 'test1'}

不过好像不行。

这是将 EXE 的输出转换为 powershell 对象集合的一种方法。它的作用...

  • 创建 exe 文件输出的假版本
  • 过滤掉重复连字符的行
  • 将前导空格替换为空
  • 用逗号替换 2 个或更多个空格
  • 将类似 CSV 的字符串数组转换为 powershell 对象的集合

这是代码 [grin] ...

# fake getting string output from an EXE
$InStuff = @'
 ------------------ ----------- ----------------
  CompanyName        CompanyId   CompanyType
 ------------------ ----------- ----------------
  test1              1           Root
  test2              2           Center
  test3              3           Company
 ------------------ ----------- ----------------
'@ -split [environment]::NewLine

$CompanyInfo = $InStuff -notmatch '--{2,}' -replace '^ {1,}' -replace ' {2,}', ',' |
    ConvertFrom-Csv

$CompanyInfo
'=' * 30
$CompanyInfo -match 'Test1'

输出...

CompanyName CompanyId CompanyType
----------- --------- -----------
test1       1         Root       
test2       2         Center     
test3       3         Company    
==============================
test1       1         Root  

PowerShell 将外部程序的输出报告为行数组(字符串)。

要使用字符串解析过滤此类输出,请使用 -match 运算符:

# Extract the line of interest with -match and a regex
PS> @(MyTool.exe companies) -match '^\s+test1\s'
test1              1           Root

注:

  • @(...),虽然这里不是绝对必要的,但确保 MyTool.exe 的输出成为一个 array,即使它恰好仅输出 one 行,以便 -match 在该数组上执行 filtering (使用标量 LHS,-match returns一个布尔值).

  • 正则表达式 ^\s+test1\s 在每一行的开头 (^) 匹配一个或多个 (+) 空白字符 (\s),后跟文字 test1,后跟空白字符 - 从而将匹配限制在 CompanyName 列。

如果要将结果解析为单独的字段:

# Extract the line of interest with -match and a regex, 
# then split that line into whitespace-separated tokens and store
# them in individual variables.
PS> $name, $id, $type = -split (@(MyTool.exe companies) -match '^\s+test1\s')
PS> $name, $id, $type  
test1
1
Root

:

  • 向您展示了如何将外部程序的输出解析为 自定义对象,您可以通过以下方式查询其 属性首先将程序的输出转换为 CSV 文本,然后通过 ConvertFrom-Csv.

    将其解析为自定义对象
    • 虽然这非常符合 PowerShell 的精神,但您不可避免地要付出性能代价,而且对于提取简单的子字符串来说,这样做可能不值得。
  • 然后,遗憾的是,放弃了将输入解析为 objects 的优势,恢复为字符串匹配,这否定了具有 属性 的优势-个性化匹配:

    • 应用-match - 字符串 运算符 - 到自定义对象 LHS 生成哈希表- like 表示 display not 适合程序化处理;例如:
      @{CompanyName=test1; CompanyId=1; CompanyType=Root}

    • 因此 - 抽象地说 - 使用 -match 会导致 误报 - 因为匹配不限于 属性 感兴趣。

简而言之:如果您不厌其烦地将输入解析为 objects - 如果有必要 - 使用它们的 properties强大的过滤,正如您在问题中尝试的那样:

  • $CompanyInfo | where {$_.CompanyName -eq 'test1'}
  • 或者,更简洁地说,使用 PSv3+ 语法:
    $CompanyInfo | where CompanyName -eq test1
  • 或者,更有效地,在 PSv4+ 中,使用 .Where() 数组方法:
    $CompanyInfo.Where({ $_.CompanyName -eq 'test1'})