I tried to create a multiline Input to practice Select-String
, expecting only a single matching line to be output, like I would normaly see it in an echo -e ... | grep
combination. But the following command still gives me both lines. It seems to be the newline is only interpreted on final ouptut and Select-String
still gets a single line of input
Write-Output "Hi`nthere" | Select-String -Pattern "i"
#
# Hi
# there
#
#
while I would expect it to return just
Hi
I used this version of PowerShell:
Get-Host | Select-Object Version
# 5.1.19041.906
Comparing with bash
I would do the following for testing commands on multiline input in bash. I usually generate multiple lines with echo -e
and then grep
processes the individual lines.
echo -e "Hi\nthere" | grep "i"
# Hi
I hope someone can explain what I miss here in PowerShell? This problem seems like a basic misconception to me, where I also was not sure what to Google for.
Edits
[edit 1]: problem also for line ending with carriage return
Write-Output "Hi`r`nthere" | Select-String -Pattern "i"
I saw that separating with commas works as valid multiline input. So maybe the question is how to convert from newline to actual input line separation.
Write-Output "Hi","there" | Select-String -Pattern "i"
# Hi
[edit 2]: from edit 1 I found this stackoverflow-answer, where for me it now works with
Write-Output "Hi`nthere".Split([Environment]::NewLine) | Select-String -Pattern "i"
# or
Write-Output "Hi`nthere".Split("`n") | Select-String -Pattern "i"
Still may someone please explain why this is relevant here, but not in bash
?
CodePudding user response:
All the information is in the comments, but let me summarize and complement it:
PowerShell's pipeline is object-based, and Select-String
operates on each input object - even if that happens to be a single multi-line string object, such as output by Write-Output "Hi`nthere"
- It is only the output from external programs that is streamed line by line.
Therefore, you must split your multi-line string into individual lines in order to match them as such.
The best idiom for that is -split '\r?\n'
, because it recognizes both Windows-format CRLF and Unix-format LF-only newlines :
"Hi`nthere" -split '\r?\n' | Select-String -Pattern "i"
Note:
I've omitted
Write-Output
in favor of PowerShell's implicit output behavior (see the bottom section of this answer for more information).For more information on how
-split '\r?\n'
works, see this answer.Select-String
doesn't directly output the matching lines (strings); instead it wraps them in match-information objects that provide metadata about each match. To get just the matching line (string):- In PowerShell (Core) 7 , add the
-Raw
switch. - In Windows PowerShell, pipe to
ForEach-Object Line
or wrap the entire call in(...).Line
- In PowerShell (Core) 7 , add the