I am using this below script in Powershell (Version is 5.1):
Get-Content -Path path\to\text\file\to\be\read.txt -Wait
Now this continues to read even after the file is getting no update. How can I stop after I find particular line in the text file? Is there any other way to stop this on condition?
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.
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.
You can pipe the output and use foreach to check each line, if the line equals a certain string you can use break
to stop the command:
Get-Content path\to\text\file\to\be\read.txt -wait | % {$_ ; if($_ -eq "yourkeyword") {break}}
For example, if you run the command above and do the following in another shell:
"yourkeyword" | Out-File path\to\text\file\to\be\read.txt -Append
The Get-Content
displays the new line and stops.
Explanation:
| %
- foreach line that is in the file or gets added to the file while the function runs
$_;
- first write out the line of the foreach then do another command
if($_ -eq "yourkeyword") {break}
- if the line of the foreach is equal to the keyword/line you want, stop the Get-Content
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With