如何在PowerShell中使用Select-String进行多重管道操作

3

我通过谷歌搜索,但没有找到我要的内容。

我有一个包含国家和人名列表的大文件。我知道如何在Linux中进行多重管道操作,但是在PowerShell中却无法奏效。

这就是我所寻找的内容,但却一无所获:

Select-String .\file -pattern 'country:[ ]{8}IR' -context 5 | Select-String -pattern 'names'

但是,如果我将这个命令分成两个部分,如下所示,则可以工作(我想避免创建一个用于搜索的文件):

Select-String .\file -pattern 'country:[ ]{8}IR' -context 5 > country
Select-String .\file -patern 'names'

*更新1

首次 grep 后的示例数据为:

  file:1407215:names:        Hadi
  file:1407216:company:        sample
  file:1407217:city:          Tehran
  file:1407218:district:          8
  file:1407219:country:        IR
  file:1407220:admin:        Mahmoud
  file:1407221:tech:         Hamed
  file:1407222:seller:        sell@company
  file:1407223:status:         Active
  file:1407224:id:         12456

1
尝试一下 Select-String .\file -pattern 'country:[ ]{8}IR' -context 5 |Where-Object {$_.Context.PostContext -match 'names'} :) - Mathias R. Jessen
@MathiasR.Jessen 不好意思,它没有起作用:( 我的意思是我没有看到“names”。什么也没看到。 - Saeed
2
啊,names行在country行之前 - 尝试使用$_.Context.PreContext而不是$_.Context.PostContext - Mathias R. Jessen
Mathias 提供的代码对我有用,如果你想进一步操作,也可以将其解析为对象。 - Santiago Squarzon
1
Where-Object 替换为 ForEach-Object,以输出匹配的前置上下文行 :) - Mathias R. Jessen
显示剩余3条评论
2个回答

1

Select-String不返回[string](或字符串数组),而是返回一个[MatchInfo]类型的对象。 MatchInfo的输出可能看起来像多行文本,但在属性.Context.PreContext.Line.Context.PostContext中分割开来。因此,您不能直接使用此对象将其管道传递到Select-String

但您可以将输出强制转换为[String],在新行处使用-split对其进行拆分,并在此数组上使用Select-String

$MatchInfo = Select-String $file -pattern 'country:[ ]{8}IR' -context 5
[string]$MatchInfo -split [environment]::NewLine | Select-String -pattern 'names'

谢谢,但是@MathiasR.Jessen所说的提供了更干净的输出。你的输出就像C:\Users\Saeed\Desktop\test\file:1407215:names: Hadi - Saeed
@Saeed 确保在不确定第二个模式是在之前还是之后时,检查前置和后置。 - T-Me
第二个模式总是在我们搜索的“country”之前。没有例外。 - Saeed

0

从PowerShell角度来看,你大多数时候都会处理对象,所以熟悉如何处理它们可能是个好主意。因此,本答案可以向你展示一种将文件解析为对象数组的替代方案,这样就可以轻松地进行操作、过滤、排序和导出结构化数据(如Csv)

假设test.txt类似于以下内容:

names:        Hadi
company:        sample
city:          Tehran
district:          8
country:        IR
admin:        Mahmoud
tech:         Hamed
seller:        sell@company
status:         Active
id:         12456

names:        John
company:        sample
city:          Tehran
district:          8
country:        IR
admin:        Doe
tech:         Hamed
seller:        sell@company
status:         Disabled
id:         12456

针对这种情况,我们可以使用带有-File参数的switch来读取文件,并使用-Regex开关来作为条件子句,以便于开始捕获将捕获数据输出为对象
$parsed = switch -Regex -File .\test.txt {
    # line starts with "names", signal to start capturing
    '^names' {
        $startcapture = $true
        $out = [ordered]@{}
    }
    # boolean is set to `$true`, capture this line and add it to the ordered dictionary
    { $startcapture } {
        $key, $value = $_.Split(':').Trim()
        $out[$key] = $value
    }
    # line starts with "id", signal to output the object, and restart the capture boolean
    '^id' {
        $startcapture = $false
        [pscustomobject] $out
    }
}

使用上述开关解析test.txt文件后,$parsed的内容如下:

names company city   district country admin   tech  seller       status   id
----- ------- ----   -------- ------- -----   ----  ------       ------   --
Hadi  sample  Tehran 8        IR      Mahmoud Hamed sell@company Active   12456
John  sample  Tehran 8        IR      Doe     Hamed sell@company Disabled 12456

现在,使用 Export-Csv 可以轻松地将 $parsed 导出为结构化数据,并使用 Import-Csv 将其作为对象导入回来:
$parsed | Export-Csv parseddata.csv -NoTypeInformation
$csv = Import-Csv parseddata.csv

它也可以非常容易地进行过滤,例如使用过滤 cmdlet Where-Object

# this array of objects where the `country` property value is equal to "IR"
# AND this array of objects where the `names` property value is equal to "Hadi"
$parsed | Where-Object { $_.country -eq 'IR' -and $_.names -eq 'Hadi' }

导致的结果是:
names    : Hadi
company  : sample
city     : Tehran
district : 8
country  : IR
admin    : Mahmoud
tech     : Hamed
seller   : sell@company
status   : Active
id       : 12456

谢谢,但由于它可能会在其他计算机上使用,而且可能会被其他不具备足够知识的人使用,我认为最好使用PowerShell中的内置命令来完成。我的意思是,我将为他们创建一个简单的脚本来运行和提取数据。 - Saeed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接