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

Rav*_*rma 3 powershell pipeline break powershell-5.0

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

Get-Content -Path path\to\text\file\to\be\read.txt -Wait
Run Code Online (Sandbox Code Playgroud)

现在,即使文件没有更新,它也会继续读取。在文本文件中找到特定行后如何停止?有没有其他方法可以阻止这种情况?

mkl*_*nt0 6

tl;博士

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.'
Run Code Online (Sandbox Code Playgroud)

请注意,-match运算符使用正则表达式( )执行子字符串匹配。about_Regular_Expressions

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


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

break/continue旨在退出/继续循环for, foreach, do, while, 和switchstatements [1]),而不是管道

从 PowerShell [Core] 7.0 开始,没有直接的方法可以提前退出管道,尽管添加此功能是GitHub 上这一长期功能请求的主题;目前,只有直接使用Select-Objectwith-First才能通过使用非公共异常提前退出管道;虽然return可以在ForEach-Object脚本块中使用,但它只退出当前的脚本块调用,同时继续处理其他管道输入。

如果您使用breakor continue,PowerShell 将查找任何封闭循环,如果没有,则脚本作为一个整体退出。

然而,如果你在你的管道[2]周围包裹一个虚拟循环,如上所示 - 其唯一目的是提供一些东西break来打破 -执行继续,如(通常)所希望的

警告

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

  • 需要清理(处置)临时持有的资源的 Cmdlet无法进行清理

    • 请注意,遗憾的是,这种无法清理也适用于使用Select-Object -First高级 PowerShell 函数/脚本(但不适用于(二进制)cmdlet,它可以通过实现System.IDisposable接口确保清理),如GitHub 问题 #7930 中所述GitHub PR #9900旨在解决引入专用cleanup块的问题。
  • 聚合cmdlet - 那些必须在能够产生输出之前收集所有输入的cmdlet -永远不会产生输出;这是一个简单的例子:

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

[1] 当您使用语句检查单个值时,如您所料switchbreak退出该语句。如果正在处理值的数组(集合),则break也立即退出该语句,而不处理数组中的其他元素continue相比之下,继续处理下一个元素。

[2] 另一种选择是用于throw生成脚本终止错误,您可以通过将管道包含在try/catch语句中来捕获该错误,如此答案中所示。但是,这具有在自动$Error集合中记录条目的副作用,即使在概念上没有发生实际错误。


Pax*_*axz 2

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

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

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

"yourkeyword" | Out-File path\to\text\file\to\be\read.txt -Append
Run Code Online (Sandbox Code Playgroud)

显示Get-Content新行并停止。


解释:

| %- foreach 函数运行时文件中的行或添加到文件中的行

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

if($_ -eq "yourkeyword") {break}- 如果 foreach 的行等于您想要的关键字/行,则停止Get-Content