在使用Powershell在文本文件中找到特定行之后,如何停止Get-Content -wait?

时间:2018-08-23 08:07:50

标签: powershell powershell-v5.0

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

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

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

2 个答案:

答案 0 :(得分:6)

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使用 regexes about_Regular_Expressions)执行 substring 匹配。

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


Paxz's answer处在正确的轨道上,但它试图(单独)使用break来退出管道,(通常)终止整个脚本 (如果您以交互方式作为单个命令提交管道,则可能不会注意到)。

break / continue旨在退出/继续循环forforeachdowhileswitch语句 [1] ),而不是管道

从PowerShell [Core] 7.0开始,没有直接方法过早退出管道 ,尽管添加此功能是this long-standing feature request on GitHub的主题;当前,通过使用非公共异常,仅将Select-Object-First直接使用才能过早退出管道;尽管return可以在ForEach-Object脚本块中使用,但它仅退出当前脚本块调用,同时继续处理其他管道输入。

如果使用breakcontinue,PowerShell将查找任何封闭循环,如果没有 ,<整个em>脚本退出。

但是,如果您将 dummy 循环包裹在管道中 [2] ,如上所示-其唯一目的是提供一些东西让break脱离-(通常)按要求继续执行

注意事项

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

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

    • 请注意,令人遗憾的是,这种无法清理也适用于将Select-Object -First与高级PowerShell函数/脚本一起使用(但不适用于(二进制)cmdlet,这可以通过实现System.IDisposable来确保清理)接口),如GitHub issue #7930中所述; GitHub PR #9900旨在解决引入专用cleanup块的问题。
  • 聚合 cmdlet-那些必需的cmdlet必须先收集 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中来捕获该错误,如this answer所示。但是,这会产生副作用,即使从概念上说没有实际的错误发生,也可以在自动$Error集合中记录一个条目。

答案 1 :(得分:1)

您可以通过管道传输输出并使用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行中的文件行或函数运行时添加到文件中的行

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

if($_ -eq "yourkeyword") {break}-如果foreach的行与所需的关键字/行相等,请停止Get-Content