使用 powershell 在文本文件中找到特定行后如何停止 Get-Content -wait?按需退出管道

How to stop Get-Content -wait after I find a particular line in the text file using powershell? Exit a pipeline on demand

我在 Powershell 中使用以下脚本(版本为 5.1):

Get-Content -Path path\to\text\file\to\be\read.txt -Wait

现在即使文件没有更新,它也会继续读取。 在文本文件中找到特定行后如何停止? 还有其他方法可以根据条件停止吗?

您可以通过管道输出并使用 foreach 检查每一行,如果该行等于某个字符串,您可以使用 break 停止命令:

Get-Content path\to\text\file\to\be\read.txt -wait | % {$_ ; if($_ -eq "yourkeyword") {break}}

例如,如果您 运行 上面的命令并在另一个 shell 中执行以下命令:

"yourkeyword" | Out-File path\to\text\file\to\be\read.txt -Append

Get-Content显示新行并停止。


解释:

| % - foreach 行在文件中或在函数 运行s

时被添加到文件中

$_; - 首先写出 foreach 的行然后执行另一个命令

if($_ -eq "yourkeyword") {break} - 如果 foreach 的行等于你想要的 keyword/line,停止 Get-Content

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.'

注意 -match operator performs substring matching using regexes (about_Regular_Expressions).

继续阅读为什么需要虚拟 do 循环。


在正确的轨道上,但是 它试图使用 break(孤立地)退出管道,这(通常)终止整个脚本(如果您以交互方式将管道作为单个命令提交,您可能不会注意到)。

break / continue 旨在退出/继续 loops (for, foreachdowhileswitch 语句 [1]),而不是 管道 .

自 PowerShell [Core] 7.2.2 起,虽然添加了此功能,但没有直接的方法提前退出管道this long-standing feature request on GitHub的主题;目前,只有直接使用 Select-Object-First 才能通过使用非 public 异常提前退出管道;虽然 return 可以在 ForEach-Object 脚本块中使用,但它只会退出当前脚本块调用,同时继续处理其他管道输入。

如果您使用 breakcontinue,PowerShell 将查找 any 封闭循环,如果有 是 none,整个 脚本 退出。

但是,如果您将 虚拟 循环包裹在管道周围[2],如上所示 - 其唯一目的是为 break 提供一些突破 - 执行 继续 ,(通常)需要 .

警告:

break / continue(和 throw)有一个重要的副作用:他们不给其他参与管道的命令正常退出的机会;也就是说,它们的 end 块/EndProcessing() 方法 未被调用 ,这在两个方面可能存在问题:

  • 需要清理(处置)临时保留资源的 Cmdlet 不清理

    • 请注意,遗憾的是,这种无法清理的情况也适用于使用 Select-Object -First 和高级 PowerShell functions/scripts(但不适用于(二进制)cmdlet,它可以通过实施 System.IDisposable interface), as discussed in GitHub issue #7930; GitHub PR #9900 旨在解决引入专用 cleanup 块的问题。
  • 聚合 cmdlets - 那些必须收集 all 输入才能产生输出 - 永远无法产生输出;这是一个简单的例子:

PS> do { 5..1 | % { $_; if ($_ -eq 3) { break } } | Sort-Object } while ($false)
# !! NO OUTPUT, because Sort-Object's EndProcessing() method was never called.

[1] 当您使用 switch 语句检查 单个 值时,break 退出该语句,就像您希望的那样预计。如果正在处理 array(一个集合)值,break 也会立即退出语句,而不处理数组中的更多元素; continue,相比之下,继续处理下一个元素。

[2] 另一种选择是使用 throw 生成脚本终止错误,您可以通过将管道包含在 try / catch statement, as shown in 中来捕获该错误。但是,这会在自动 $Error 集合中记录一个条目,即使 概念上 没有实际错误发生。