tl;dr
do {
Get-Content -Path path\to\text\file\to\be\read.txt -Wait | ForEach-Object {
# Pass the input line through.
$_
# Exit once the string of interest is found.
if ($_ -match 'patternOfInterest') { break }
}
} while ($false) # dummy loop so that `break` can be used.
# NOTE: Without the dummy `do` loop, this code would not be reached.
'Line of interest found.'
Note that the -match
operator performs substring matching using regexes (about_Regular_Expressions
).
Read on for why the dummy do
loop is needed.
Paxz's answer is on the right track, but it tries to use break
(in isolation) to exit the pipeline, which (typically) terminates the whole script (if you submit the pipeline as a single command interactively, you may not notice).
break
/ continue
are designed to exit / continue loops (for
, foreach
, do
, while
, and switch
statements[1]), not pipelines.
As of PowerShell [Core] 7.2.2, there is no direct way to exit a pipeline prematurely, though adding this feature is the subject of this long-standing feature request on GitHub; currently, only direct use of Select-Object
with -First
can exit a pipeline prematurely, through use of non-public exception; while return
can be used in a ForEach-Object
script block, it only exits the current script-block invocation while continuing to process additional pipeline input.
If you use break
or continue
, PowerShell will look for any enclosing loop and if there is none, the script as a whole exits.
However, if you wrap a dummy loop around your pipeline[2], as shown above - whose sole purpose is to provide something for break
to break out of - execution continues, as (usually) desired.
Caveat:
break
/ continue
(and throw
) have an important side effect: they do not give the other commands participating in the pipeline a chance to exit normally; that is, their end
blocks / EndProcessing()
methods are not called, which can be problematic in two respects:
Cmdlets that need to clean up (dispose of) temporarily held resources do not get to clean up.
- Note that, regrettably, this inability to clean up also applies to use of
Select-Object -First
with advanced PowerShell functions/scripts (but not with (binary) cmdlets, which can ensure cleanup by implementing the System.IDisposable
interface), as discussed in GitHub issue #7930; GitHub PR #9900 aims to address that introducing a dedicated cleanup
block.
Aggregating cmdlets - those that of necessity collect all input before being able to produce output - never get to produce output; here's a simple example:
PS> do { 5..1 | % { $_; if ($_ -eq 3) { break } } | Sort-Object } while ($false)
# !! NO OUTPUT, because Sort-Object's EndProcessing() method was never called.
[1] When you examine a single value with a switch
statement, break
exits the statement, as you would expect. If an array (a collection) of values is being processed, break
too exits the statement immediately, without processing further elements in the array; continue
, by contrast, continues processing with the next element.
[2] Another option is to use throw
to generate a script-terminating error that you catch by enclosing the pipeline in a try
/ catch
statement, as shown in this answer. However, this has the side effect of recording an entry in the automatic $Error
collection, even though conceptually no actual error occurred.