使用 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
, foreach
、do
、while
和 switch
语句 [1]),而不是 管道 .
自 PowerShell [Core] 7.2.2 起,虽然添加了此功能,但没有直接的方法提前退出管道是this long-standing feature request on GitHub的主题;目前,只有直接使用 Select-Object
和 -First
才能通过使用非 public 异常提前退出管道;虽然 return
可以在 ForEach-Object
脚本块中使用,但它只会退出当前脚本块调用,同时继续处理其他管道输入。
如果您使用 break
或 continue
,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
集合中记录一个条目,即使 概念上 没有实际错误发生。
我在 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
, foreach
、do
、while
和 switch
语句 [1]),而不是 管道 .
自 PowerShell [Core] 7.2.2 起,虽然添加了此功能,但没有直接的方法提前退出管道是this long-standing feature request on GitHub的主题;目前,只有直接使用 Select-Object
和 -First
才能通过使用非 public 异常提前退出管道;虽然 return
可以在 ForEach-Object
脚本块中使用,但它只会退出当前脚本块调用,同时继续处理其他管道输入。
如果您使用 break
或 continue
,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
集合中记录一个条目,即使 概念上 没有实际错误发生。