代理命令,分流命令

huangapple go评论100阅读模式
英文:

Proxy command that tees

问题

对于一个 PowerShell 功能请求(无论这是否是个好主意),我尝试创建了一个原型,使用了一个名为 Write-Table 的代理命令,基于 Format-Table 命令,它直接将数据写入主机,并根据 PassThru 开关的情况应该传递当前输入对象:

  1. function Write-Table {
  2. [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkID=2096703')]
  3. param(
  4. [switch]
  5. ${AutoSize},
  6. [switch]
  7. ${RepeatHeader},
  8. [switch]
  9. ${HideTableHeaders},
  10. [switch]
  11. ${Wrap},
  12. [Parameter(Position=0)]
  13. [System.Object[]]
  14. ${Property},
  15. [System.Object]
  16. ${GroupBy},
  17. [string]
  18. ${View},
  19. [switch]
  20. ${ShowError},
  21. [switch]
  22. ${DisplayError},
  23. [switch]
  24. ${Force},
  25. [ValidateSet('CoreOnly','EnumOnly','Both')]
  26. [string]
  27. ${Expand},
  28. [Parameter(ValueFromPipeline=$true)]
  29. [psobject]
  30. ${InputObject},
  31. [switch]
  32. ${PassThru})
  33. begin
  34. {
  35. try {
  36. $outBuffer = $null
  37. if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
  38. {
  39. $PSBoundParameters['OutBuffer'] = 1
  40. }
  41. if ($PSBoundParameters.TryGetValue('PassThru', [ref]$outBuffer))
  42. {
  43. $Null = $PSBoundParameters.Remove('PassThru')
  44. }
  45. $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Utility\Format-Table', [System.Management.Automation.CommandTypes]::Cmdlet)
  46. $scriptCmd = {& $wrappedCmd @PSBoundParameters }
  47. $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  48. $steppablePipeline.Begin($PSCmdlet)
  49. } catch {
  50. throw
  51. }
  52. }
  53. process
  54. {
  55. try {
  56. if ($PassThru) { $_ }
  57. $steppablePipeline.Process($_)
  58. } catch {
  59. throw
  60. }
  61. }
  62. end
  63. {
  64. try {
  65. $steppablePipeline.End()
  66. } catch {
  67. throw
  68. }
  69. }
  70. clean
  71. {
  72. if ($null -ne $steppablePipeline) {
  73. $steppablePipeline.Clean()
  74. }
  75. }
  76. <#
  77. .ForwardHelpTargetName Microsoft.PowerShell.Utility\Format-Table
  78. .ForwardHelpCategory Cmdlet
  79. #>
  80. }

但不知何故,似乎当前的对象在传递给主机之前已从管道中移除(我不知道如何防止这种情况发生):

  1. gci *.txt | Write-Table -PassThru | Get-Item # 最终意图: ... | Remove-Item
  2. Directory: C:\Users\Gebruiker\Downloads\temp
  3. Mode LastWriteTime Length Name
  4. ---- ------------- ------ ----
  5. -a--- 7/20/2023 3:44 PM 0 file1.txt
  6. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.FormatStartData' because it does not exist.
  7. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.GroupStartData' because it does not exist.
  8. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData' because it does not exist.
  9. -a--- 7/20/2023 3:44 PM 0 file2.txt
  10. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData' because it does not exist.
  11. -a--- 7/20/2023 3:44 PM 0 file3.txt
  12. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData' because it does not exist.
  13. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.GroupEndData' because it does not exist.
  14. Get-Item: Cannot find path 'Microsoft.PowerShell.Commands.Internal.Format.FormatEndData' because it does not exist.
  15. 是否有人能解释这里发生了什么问题以及如何解决
  16. <details>
  17. <summary>英文:</summary>
  18. For a [PowerShell feature request](https://github.com/PowerShell/PowerShell/issues/20001) (whether this is a good idea or not), I tried to create a prototype using a proxy command named `Write-Table` based on the `Format-Table` cmdlet that directly writes to the host and depending on the `PassThru` switch should pass the current input object:
  19. function Write-Table {
  20. [CmdletBinding(HelpUri=&#39;https://go.microsoft.com/fwlink/?LinkID=2096703&#39;)]
  21. param(
  22. [switch]
  23. ${AutoSize},
  24. [switch]
  25. ${RepeatHeader},
  26. [switch]
  27. ${HideTableHeaders},
  28. [switch]
  29. ${Wrap},
  30. [Parameter(Position=0)]
  31. [System.Object[]]
  32. ${Property},
  33. [System.Object]
  34. ${GroupBy},
  35. [string]
  36. ${View},
  37. [switch]
  38. ${ShowError},
  39. [switch]
  40. ${DisplayError},
  41. [switch]
  42. ${Force},
  43. [ValidateSet(&#39;CoreOnly&#39;,&#39;EnumOnly&#39;,&#39;Both&#39;)]
  44. [string]
  45. ${Expand},
  46. [Parameter(ValueFromPipeline=$true)]
  47. [psobject]
  48. ${InputObject},
  49. [switch]
  50. ${PassThru})
  51. begin
  52. {
  53. try {
  54. $outBuffer = $null
  55. if ($PSBoundParameters.TryGetValue(&#39;OutBuffer&#39;, [ref]$outBuffer))
  56. {
  57. $PSBoundParameters[&#39;OutBuffer&#39;] = 1
  58. }
  59. if ($PSBoundParameters.TryGetValue(&#39;PassThru&#39;, [ref]$outBuffer))
  60. {
  61. $Null = $PSBoundParameters.Remove(&#39;PassThru&#39;)
  62. }
  63. $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand(&#39;Microsoft.PowerShell.Utility\Format-Table&#39;, [System.Management.Automation.CommandTypes]::Cmdlet)
  64. $scriptCmd = {&amp; $wrappedCmd @PSBoundParameters }
  65. $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  66. $steppablePipeline.Begin($PSCmdlet)
  67. } catch {
  68. throw
  69. }
  70. }
  71. process
  72. {
  73. try {
  74. if ($PassThru) { $_ }
  75. $steppablePipeline.Process($_)
  76. } catch {
  77. throw
  78. }
  79. }
  80. end
  81. {
  82. try {
  83. $steppablePipeline.End()
  84. } catch {
  85. throw
  86. }
  87. }
  88. clean
  89. {
  90. if ($null -ne $steppablePipeline) {
  91. $steppablePipeline.Clean()
  92. }
  93. }
  94. &lt;#
  95. .ForwardHelpTargetName Microsoft.PowerShell.Utility\Format-Table
  96. .ForwardHelpCategory Cmdlet
  97. #&gt;
  98. }
  99. But somehow it appears that the current object is removed from the pipeline before it is also passed to the host (I have no clue how to prevent that)
  100. gci *.txt | Write-Table -PassThru | Get-Item # Final intention: ... | Remove-Item
  101. Directory: C:\Users\Gebruiker\Downloads\temp
  102. Mode LastWriteTime Length Name
  103. ---- ------------- ------ ----
  104. -a--- 7/20/2023 3:44 PM 0 file1.txt
  105. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.FormatStartData&#39; because it does not exist.
  106. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.GroupStartData&#39; because it does not exist.
  107. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData&#39; because it does not exist.
  108. -a--- 7/20/2023 3:44 PM 0 file2.txt
  109. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData&#39; because it does not exist.
  110. -a--- 7/20/2023 3:44 PM 0 file3.txt
  111. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData&#39; because it does not exist.
  112. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.GroupEndData&#39; because it does not exist.
  113. Get-Item: Cannot find path &#39;Microsoft.PowerShell.Commands.Internal.Format.FormatEndData&#39; because it does not exist.
  114. Does anyone have an explanation where this goes sideways and how I might resolve this?
  115. </details>
  116. # 答案1
  117. **得分**: 2
  118. 以下是您要翻译的部分
  119. 看起来对包装的命令稍作更新应该能解决您的问题如果我理解正确`Format-Table` 生成的输出应该直接发送到主机因此需要添加 `Out-Host`然后如果存在 `-PassThru`您很可能希望将原始对象发送到管道中因此
  120. ```sh
  121. function Write-Table {
  122. [CmdletBinding(HelpUri = 'https://go.microsoft.com/fwlink/?LinkID=2096703')]
  123. param(
  124. [switch]
  125. ${AutoSize},
  126. [switch]
  127. ${RepeatHeader},
  128. [switch]
  129. ${HideTableHeaders},
  130. [switch]
  131. ${Wrap},
  132. [Parameter(Position = 0)]
  133. [System.Object[]]
  134. ${Property},
  135. [System.Object]
  136. ${GroupBy},
  137. [string]
  138. ${View},
  139. [switch]
  140. ${ShowError},
  141. [switch]
  142. ${DisplayError},
  143. [switch]
  144. ${Force},
  145. [ValidateSet('CoreOnly', 'EnumOnly', 'Both')]
  146. [string]
  147. ${Expand},
  148. [Parameter(ValueFromPipeline = $true)]
  149. [psobject]
  150. ${InputObject},
  151. [switch]
  152. ${PassThru})
  153. begin {
  154. $null = $PSBoundParameters.Remove('PassThru')
  155. $scriptCmd = { Microsoft.PowerShell.Utility\Format-Table @PSBoundParameters | Out-Host }
  156. $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  157. $steppablePipeline.Begin($PSCmdlet)
  158. }
  159. process {
  160. if ($PassThru.IsPresent) {
  161. $InputObject
  162. }
  163. $steppablePipeline.Process($InputObject)
  164. }
  165. end {
  166. $steppablePipeline.End()
  167. }
  168. clean {
  169. if ($null -ne $steppablePipeline) {
  170. $steppablePipeline.Clean()
  171. }
  172. }
  173. &lt;#
  174. .ForwardHelpTargetName Microsoft.PowerShell.Utility\Format-Table
  175. .ForwardHelpCategory Cmdlet
  176. #&gt;
  177. }

然后,类似这样的代码:

  1. $capture = 0..5 | ForEach-Object { [pscustomobject]@{ Item = $_ } } |
  2. Write-Table -PassThru |
  3. ForEach-Object Item

可以正常工作:

  1. PS ..\pwsh&gt; $capture = 0..10 | ForEach-Object { [pscustom.... # 输出发送到主机: Item ---- 0 1 2 3 4 5
  2. PS ..\pwsh&gt; $capture
  3. 0
  4. 1
  5. 2
  6. 3
  7. 4
  8. 5
  9. 6
  10. 7
  11. 8
  12. 9
  13. 10
英文:

It seems a little update to the wrapped command should solve your problem if I'm understanding correctly, the output generated by Format-Table should go directly to the host, thus adding Out-Host. Then if -PassThru is present you more than likely want to send the original object thru the pipeline so:

  1. function Write-Table {
  2. [CmdletBinding(HelpUri = &#39;https://go.microsoft.com/fwlink/?LinkID=2096703&#39;)]
  3. param(
  4. [switch]
  5. ${AutoSize},
  6. [switch]
  7. ${RepeatHeader},
  8. [switch]
  9. ${HideTableHeaders},
  10. [switch]
  11. ${Wrap},
  12. [Parameter(Position = 0)]
  13. [System.Object[]]
  14. ${Property},
  15. [System.Object]
  16. ${GroupBy},
  17. [string]
  18. ${View},
  19. [switch]
  20. ${ShowError},
  21. [switch]
  22. ${DisplayError},
  23. [switch]
  24. ${Force},
  25. [ValidateSet(&#39;CoreOnly&#39;, &#39;EnumOnly&#39;, &#39;Both&#39;)]
  26. [string]
  27. ${Expand},
  28. [Parameter(ValueFromPipeline = $true)]
  29. [psobject]
  30. ${InputObject},
  31. [switch]
  32. ${PassThru})
  33. begin {
  34. $null = $PSBoundParameters.Remove(&#39;PassThru&#39;)
  35. $scriptCmd = { Microsoft.PowerShell.Utility\Format-Table @PSBoundParameters | Out-Host }
  36. $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
  37. $steppablePipeline.Begin($PSCmdlet)
  38. }
  39. process {
  40. if ($PassThru.IsPresent) {
  41. $InputObject
  42. }
  43. $steppablePipeline.Process($InputObject)
  44. }
  45. end {
  46. $steppablePipeline.End()
  47. }
  48. clean {
  49. if ($null -ne $steppablePipeline) {
  50. $steppablePipeline.Clean()
  51. }
  52. }
  53. &lt;#
  54. .ForwardHelpTargetName Microsoft.PowerShell.Utility\Format-Table
  55. .ForwardHelpCategory Cmdlet
  56. #&gt;
  57. }

Then something like this:

  1. $capture = 0..5 | ForEach-Object { [pscustomobject]@{ Item = $_ } } |
  2. Write-Table -PassThru |
  3. ForEach-Object Item

Works just fine:

  1. PS ..\pwsh&gt; $capture = 0..10 | ForEach-Object { [pscustom....
  2. # Output sent to the host:
  3. Item
  4. ----
  5. 0
  6. 1
  7. 2
  8. 3
  9. 4
  10. 5
  11. PS ..\pwsh&gt; $capture
  12. 0
  13. 1
  14. 2
  15. 3
  16. 4
  17. 5
  18. 6
  19. 7
  20. 8
  21. 9
  22. 10

huangapple
  • 本文由 发表于 2023年7月20日 22:32:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76730959.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定