How to Select-String multiline?
Solution 1
Select-String
operates on its input objects individually, and if you either pass a file path directly to it (via -Path
or -LiteralPath
) or you pipe output from Get-Content
, matching is performed on each line.
Therefore, pass your input as a single, multiline string, which, if it comes from a file, is most easily achieved with Get-Content -Raw
(PSv3+):
Get-Content -Raw file.txt | Select-String -Pattern Line1
Note that this means that if the pattern matches, the file's entire content is output, accessible via the output object's .Line
property.
By contrast, if you want to retain per-line matching but also capture a fixed number of surrounding lines, use the -Context
parameter.
Get-Content file.txt | Select-String -Pattern Line1 -Context 0, 2
Ansgar Wiechers' helpful answer shows how to extract all the lines from the result.
Solution 2
Select-String
allows to select a given number of lines before or after the matching line via the parameter -Context
. -Context 2,0
selects the preceding 2 lines, -Context 0,2
selects the subsequent 2 lines, -Context 2,2
selects the 2 lines before as well as the 2 lines after the match.
You won't get match and context lines in one big lump, though, so you need to combine matched line and context if you want them as a single string:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
$($_.Line; $_.Context.PostContext) | Out-String
}
As @mklement0 correctly pointed out in the comments, the above is comparatively slow, which isn't a problem if you're only processing a few matches, but becomes an issue if you need to process hundreds or thousands of matches. To improve performance you can merge the values into a single array and use the -join
operator:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
(,$_.Line + $_.Context.PostContext) -join [Environment]::NewLine
}
Note that the two code snippets don't produce the exact same result, because Out-String
appends a newline to each line including the last one, whereas -join
only puts newlines between lines (not at the end of the last one). Each snippet can be modified to produce the same result as the other, though. Trim the strings from the first example to remove trailing newlines, or append another newline to the strings from the second one.
If you want the output as individual lines just output the Line
and PostContext
properties without merging them into one string:
Select-String -Pattern 'Line1' -Context 0,2 | ForEach-Object {
$_.Line
$_.Context.PostContext
}
vanillacoke9191
Updated on July 18, 2022Comments
-
vanillacoke9191 almost 2 years
I am trying to
Select-String
on a text that is on multiple lines.Example:
"This is line1 <Test>Testing Line 2</Test> <Test>Testing Line 3</Test>"
I want to be able to select all 3 lines in
Select-String
. However, it is only selecting the first line when I doSelect-String -Pattern "Line1"
. How can I extract all 3 lines together?Select-String -Pattern "Line1"
-
metablaster about 3 years
Select-String operates on its input objects individually
this is critical point! -
js2010 over 2 yearsAlso weird things happen at the prompt vs a script. At the prompt, select-string looks for
\r
at the ends of lines of raw strings in windows, and there's the problem of pasting tabs or inserting literal tabs at the prompt.