iRo*_*Ron 4 powershell pipeline
在我们公司,我是个新人,他们几乎为每个 Native PowerShell cmdlet 都有一个包装器,主要是为了添加更多日志记录和错误处理。我试图反驳这一点,并参考内部 PowerShell 功能来创建一个代理命令,例如:
$GCI = Get-Command Get-ChildItem
[System.Management.Automation.ProxyCommand]::Create($GCI)
Run Code Online (Sandbox Code Playgroud)
但我在这里缺乏一些知识。
SteppablePipeline 和使用本机 PowerShell 语法之间有什么区别(如果有)。
换句话说,在Process块中,有什么区别:
$steppablePipeline.Process($_)
Run Code Online (Sandbox Code Playgroud)
并使用本机 PowerShell 语法:
$_ |Microsoft.PowerShell.Management\Get-ChildItem # In this example
Run Code Online (Sandbox Code Playgroud)
我知道我正在寻找一般信息,但在我看来,几乎没有任何关于例如ScriptBlock.GetSteppablePipeline方法的信息
\n
这篇 2009 年的著名博客文章介绍了代理函数(包装函数),解释了需要可步进管道来实现它们;以下引用表明(但没有明确说明)它们可能是为此目的而创建的:
\n\n\n特别是,您希望能够控制调用命令 \xe2\x80\x93 的执行,以控制 \xe2\x80\x99 何时 BEGINPROCESS()、PROCESSRECORD()、ENDPROCESS() 等方法被称为
\n
简而言之,代理函数通过可步进管道,允许您以内存高效、流式传输的方式将大部分实现委托给另一个cmdlet ,从而实现 cmdlet(高级功能) 。
\n具体来说,可步进管道允许您将代理函数的实现委托给脚本块,该脚本块的生命周期在初始化(块)、每个对象管道输入处理(块)方面与代理函数本身保持同步,和终止(块),这意味着包装的 cmdlet 的单个实例实际上直接连接到与代理函数本身相同的管道。beginprocessend
相反,这意味着:在以下场景中,您并不严格需要代理函数来编写包装函数:
\n如果您的包装函数不需要支持管道输入。
\n如果您不介意先收集所有管道输入,然后再将其全部传递给包装函数的块中的包装 cmdlet end,这意味着您将放弃流处理
processFormat-*cmdlet 或聚合 cmdlet,例如Sort-Object和Group-Object以下是包装函数around的三种不同实现Select-String,它仅将每个匹配行的匹配部分报告为字符串,以说明权衡:
Select-MatchProxy是一个适当的代理函数,即它Select-String通过可步进管道进行调用,这相当于仅涉及的单个调用实例化的流处理Select-String。
[System.Management.Automation.ProxyCommand]::Create((Get-Commmand \'Select-String\'))。[System.Management.Automation.ProxyCommand]::Create()。Select-MatchSimpleSelect-String每个块中调用一个新的实例process,这也相当于流式处理,但性能较差;如上所述,这种实现方法并不总是可行,具体取决于所包装的 cmdlet。
Select-MatchCollect预先收集所有管道输入,然后将其传递到块Select-String中end,这会放弃流处理并且占用大量内存;然而,就运行时而言,它实际上比代理功能表现得稍好一些。
function Select-MatchProxy {\n [CmdletBinding(PositionalBinding=$false)]\n param(\n [Parameter(Mandatory, ValueFromPipeline)]\n $InputObject,\n [Parameter(Mandatory, Position=0)]\n [string] $Pattern\n )\n begin {\n $steppablePipeline = { \n Select-String -Pattern $Pattern | ForEach-Object { $_.Matches.Value }\n }.GetSteppablePipeline($myInvocation.CommandOrigin)\n $steppablePipeline.Begin($PSCmdlet)\n }\n process {\n $steppablePipeline.Process($InputObject)\n }\n end {\n $steppablePipeline.End()\n }\n}\n\nfunction Select-MatchSimple {\n [CmdletBinding(PositionalBinding=$false)]\n param(\n [Parameter(Mandatory, ValueFromPipeline)]\n $InputObject,\n [Parameter(Mandatory, Position=0)]\n [string] $Pattern\n )\n process {\n Select-String -InputObject $InputObject -Pattern $Pattern |\n ForEach-Object {\n $_.Matches.Value\n }\n }\n}\n\nfunction Select-MatchCollect {\n [CmdletBinding(PositionalBinding=$false)]\n param(\n [Parameter(Mandatory, ValueFromPipeline)]\n $InputObject,\n [Parameter(Mandatory, Position=0)]\n [string] $Pattern\n )\n begin {\n $l = [System.Collections.Generic.List[object]]::new()\n }\n process {\n $l.Add($InputObject)\n }\n end {\n $l | Select-String -Pattern $Pattern | ForEach-Object { $_.Matches.Value }\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n要比较运行时间,可以使用以下代码:
\n# Sample input array of 100,000 strings.\n$array = (\'foo\', \'bar\') * 50000\n# Time 15 runs of each function, and report the average.\nTime-Command { $array | Select-MatchProxy \'o+\' }, \n { $array | Select-MatchSimple \'o+\' }, \n { $array | Select-MatchCollect \'o+\' }\nRun Code Online (Sandbox Code Playgroud)\n运行 PowerShell Core 7.3.0-preview.6 的 macOS 12.4 M1 Mac 的示例计时,可了解相对性能:
\nFactor Secs (15-run avg.) Command TimeSpan\n------ ------------------ ------- --------\n1.00 0.916 $array | Select-MatchCollect \'o+\' 00:00:00.9162298\n1.12 1.025 $array | Select-MatchProxy \'o+\' 00:00:01.0254835\n5.38 4.930 $array | Select-MatchSimple \'o+\' 00:00:04.9298495\nRun Code Online (Sandbox Code Playgroud)\n上面使用了这个 GistTime-Command中的函数。
假设您已经查看了链接的 Gist 的源代码以确保它是安全的(我个人可以向您保证,但您应该始终检查),您可以直接安装它,如下所示:
\nirm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex\nRun Code Online (Sandbox Code Playgroud)\n| 归档时间: |
|
| 查看次数: |
662 次 |
| 最近记录: |