我正在尝试Select-String
多行的文本。
例:
"This is line1
<Test>Testing Line 2</Test>
<Test>Testing Line 3</Test>"
我希望能够在Select-String
中选择所有 3 行。但是,它仅在我执行Select-String -Pattern "Line1"
时选择第一行。如何将所有 3 行提取在一起?
Select-String -Pattern "Line1"
>Select-String
单独对其输入对象进行操作,如果您将文件路径直接传递给它(通过-Path
或-LiteralPath
),或者从Get-Content
通过管道输出,则在每行上执行匹配。
因此,将您的输入作为单个多行字符串传递,如果它来自文件,则最容易通过Get-Content -Raw
(PSv3+) 实现:
Get-Content -Raw file.txt | Select-String -Pattern Line1
请注意,这意味着如果模式匹配,则输出文件的整个内容,可通过输出对象的.Line
属性访问。
相比之下,如果要保留每行匹配,但同时捕获固定数量的周围线条,请使用-Context
参数。
Get-Content file.txt | Select-String -Pattern Line1 -Context 0, 2
Ansgar Wiechers的有用答案显示了如何从结果中提取所有线条。
Select-String
允许通过参数-Context
在匹配行之前或之后选择给定数量的行。-Context 2,0
选择前面的 2 行,-Context 0,2
选择后面的 2 行,-Context 2,2
选择匹配前的 2 行以及匹配后的 2 行。
但是,您不会在一个大块中获得匹配行和上下文行,因此如果您希望将它们作为单个字符串,则需要将它们组合在一起:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
$($_.Line; $_.Context.PostContext) | Out-String
}
正如@mklement0评论中正确指出的那样,上面的内容相对较慢,如果您只处理几个匹配项,这不是问题,但如果您需要处理数百或数千个匹配项,则会出现问题。若要提高性能,可以将值合并到单个数组中,并使用-join
运算符:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
(,$_.Line + $_.Context.PostContext) -join [Environment]::NewLine
}
请注意,这两个代码片段不会产生完全相同的结果,因为Out-String
在每一行(包括最后一行)附加一个换行符,而-join
只在行之间放置换行符(而不是在最后一行的末尾)。但是,可以修改每个代码段以产生与另一个代码段相同的结果。修剪第一个示例中的字符串以删除尾随换行符,或将另一个换行符附加到第二个示例中的字符串。
如果您希望输出为单独的行,只需输出Line
和PostContext
属性,而无需将它们合并到一个字符串中:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
$_.Line
$_.Context.PostContext
}