是否可以从过滤器内终止或停止 PowerShell 管道
我编写了一个简单的 PowerShell 过滤器,如果当前对象的日期在指定的开始日期和结束日期之间,则该过滤器会将当前对象推入管道。 管道中的对象始终按日期升序排列,因此一旦日期超过指定的结束日期,我就知道我的工作已完成,我想告诉管道上游命令可以放弃其工作,以便管道可以完成它的工作。 我正在阅读一些非常大的日志文件,并且经常只想检查日志的一部分。 我很确定这是不可能的,但我想问一下以确定。
I have written a simple PowerShell filter that pushes the current object down the pipeline if its date is between the specified begin and end date. The objects coming down the pipeline are always in ascending date order so as soon as the date exceeds the specified end date I know my work is done and I would like to let tell the pipeline that the upstream commands can abandon their work so that the pipeline can finish its work. I am reading some very large log files and I will frequently want to examine just a portion of the log. I am pretty sure this is not possible but I wanted to ask to be sure.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
可以用任何会破坏外部循环或完全停止脚本执行(例如抛出异常)的东西来破坏管道。 解决方案是将管道包装在一个循环中,如果需要停止管道,可以中断该循环。
例如,下面的代码将从管道中返回第一项,然后通过中断外部 do-while 循环来中断管道:
此功能可以包装到这样的函数中,其中最后一行完成与上面相同的操作:
It is possible to break a pipeline with anything that would otherwise break an outside loop or halt script execution altogether (like throwing an exception). The solution is to wrap the pipeline in a loop that you can break if you need to stop the pipeline.
For example, the below code will return the first item from the pipeline and then break the pipeline by breaking the outside do-while loop:
This functionality can be wrapped into a function like this, where the last line accomplishes the same thing as above:
这是一个不完美的
Stop-Pipeline
cmdlet 实现(需要 PS v3+),非常感谢改编自 这个答案:警告:我不完全理解它是如何工作的,尽管从根本上来说它利用了
Select -First
过早停止管道的能力(PS v3+)。 但是,在这种情况下,Select -First
终止管道的方式存在一个关键区别:下游 cmdlet(命令稍后位于pipeline)没有机会运行它们的end
块。因此,聚合 cmdlet(在生成输出之前必须接收所有输入的 cmdlet,例如
Sort-Object
、Group-Object 和
Measure-Object
)如果稍后放置在同一管道中,将不会产生输出; 例如:可能带来更好解决方案的背景信息:
感谢PetSerAl,我的此处的答案展示了如何生成
Select-Object -First
在内部使用来停止上游 cmdlet 的相同异常。但是,异常是从本身连接到管道以停止的 cmdlet 内部引发的,但此处的情况并非如此:
Stop-Pipeline
,如上面的示例中,是否未连接到应停止的管道(仅封闭的ForEach-Object
(%
) 块连接到),因此问题是:如何在目标管道的上下文中抛出异常?Here's an - imperfect - implementation of a
Stop-Pipeline
cmdlet (requires PS v3+), gratefully adapted from this answer:Caveat: I don't fully understand how it works, though fundamentally it takes advantage of
Select -First
's ability to stop the pipeline prematurely (PS v3+). However, in this case there is one crucial difference to howSelect -First
terminates the pipeline: downstream cmdlets (commands later in the pipeline) do not get a chance to run theirend
blocks.Therefore, aggregating cmdlets (those that must receive all input before producing output, such as
Sort-Object
,Group-Object
, andMeasure-Object
) will not produce output if placed later in the same pipeline; e.g.:Background info that may lead to a better solution:
Thanks to PetSerAl, my answer here shows how to produce the same exception that
Select-Object -First
uses internally to stop upstream cmdlets.However, there the exception is thrown from inside the cmdlet that is itself connected to the pipeline to stop, which is not the case here:
Stop-Pipeline
, as used in the examples above, is not connected to the pipeline that should be stopped (only the enclosingForEach-Object
(%
) block is), so the question is: How can the exception be thrown in the context of the target pipeline?无法从下游命令停止上游命令。它将继续过滤掉与您的条件不匹配的对象,但第一个命令将处理它设置为处理的所有内容。
解决方法是对上游 cmdlet 或函数/过滤器进行更多过滤。 使用日志文件会使事情变得更加复杂,但也许使用 Select-String 和正则表达式来过滤掉不需要的日期可能对您有用。
除非您知道要读取多少行以及从哪里读取,否则将读取整个文件以检查模式。
It is not possible to stop an upstream command from a downstream command.. it will continue to filter out objects that do not match your criteria, but the first command will process everything it was set to process.
The workaround will be to do more filtering on the upstream cmdlet or function/filter. Working with log files makes it a bit more comoplicated, but perhaps using Select-String and a regular expression to filter out the undesired dates might work for you.
Unless you know how many lines you want to take and from where, the whole file will be read to check for the pattern.
结束管道时可以抛出异常。
或者
查看这篇关于如何终止管道的文章:https://web.archive.org/web/20160829015320/http://powershell.com/cs/blogs/tobias/archive/2010/ 01/01/cancelling-a-pipeline.aspx
You can throw an exception when ending the pipeline.
or
Look at this post about how to terminate a pipeline: https://web.archive.org/web/20160829015320/http://powershell.com/cs/blogs/tobias/archive/2010/01/01/cancelling-a-pipeline.aspx
不确定您的确切需求,但可能值得您花时间查看 日志解析器 查看是否无法在数据到达管道之前使用查询来过滤数据。
Not sure about your exact needs, but it may be worth your time to look at Log Parser to see if you can't use a query to filter the data before it even hits the pipe.
如果您愿意使用非公共成员,这里是停止管道的一种方法。 它模仿了
select-object
的作用。invoke-method
(别名im
)是一个调用非公共方法的函数。select-property
(别名selp
)是一个选择(类似于select-object)非公共属性的函数 - 但它自动作用类似于-ExpandProperty
code> 如果只找到一个匹配的属性。 (我在工作中编写了select-property
和invoke-method
,因此无法分享它们的源代码)。编辑:根据 mklement0 的评论:
这是一个 链接到“poke”模块上脚本上的 Nivot ink 博客,该模块同样允许非公开成员访问。
至于其他评论,我目前没有有意义的评论。 这段代码只是模仿
select-object
的反编译所揭示的内容。 原始的MS注释(如果有的话)当然不在反编译中。 坦率地说,我不知道该函数使用的各种类型的用途。 获得这种程度的理解可能需要付出相当大的努力。我的建议:获取 Oisin 的 Poke 模块。 调整代码以使用该模块。 然后尝试一下。 如果您喜欢它的工作方式,那么就使用它,不用担心它是如何工作的(这就是我所做的)。
注意:我没有深入研究过“poke”,但我的猜测是它没有像
-returnClosure
这样的东西。 但是添加它应该很容易,如下所示:If you're willing to use non-public members here is a way to stop the pipeline. It mimics what
select-object
does.invoke-method
(aliasim
) is a function to invoke non-public methods.select-property
(aliasselp
) is a function to select (similar to select-object) non-public properties - however it automatically acts like-ExpandProperty
if only one matching property is found. (I wroteselect-property
andinvoke-method
at work, so can't share the source code of those).EDIT: per mklement0's comment:
Here is a link to the Nivot ink blog on a script on the "poke" module which similarly gives access to non-public members.
As far as additional comments, I don't have meaningful ones at this point. This code just mimics what a decompilation of
select-object
reveals. The original MS comments (if any) are of course not in the decompilation. Frankly I don't know the purpose of the various types the function uses. Getting that level of understanding would likely require a considerable amount of effort.My suggestion: get Oisin's poke module. Tweak the code to use that module. And then try it out. If you like the way it works, then use it and don't worry how it works (that's what I did).
Note: I haven't studied "poke" in any depth, but my guess is that it doesn't have anything like
-returnClosure
. However adding that should be easy as this:尝试这些过滤器,它们将强制管道在第一个对象(或前 n 个元素)之后停止并将其存储在变量中; 您需要传递变量的名称,如果不传递,则对象将被推出但无法分配给变量。
Try these filters, they'll force the pipeline to stop after the first object -or the first n elements- and store it -them- in a variable; you need to pass the name of the variable, if you don't the object(s) are pushed out but cannot be assigned to a variable.
另一种选择是在
switch
语句上使用-file
参数。 使用-file
将一次读取文件一行,您可以使用break
立即退出,而不读取文件的其余部分。Another option would be to use the
-file
parameter on aswitch
statement. Using-file
will read the file one line at a time, and you can usebreak
to exit immediately without reading the rest of the file.