![](/img/trans.png)
[英]How to pass argument to a function from a pipe output of another using powershell
[英]How to pass the 'argument-line' of one PowerShell function to another?
我正在尝试编写一些 PowerShell 函数来做一些事情,然后透明地调用现有的内置函数。 我想原封不动地传递所有论点。 我不想知道论点的任何细节。
我厌倦了使用 'splat' 来用@args
来做这@args
但这并没有像我预期的那样工作。
在下面的示例中,我编写了一个名为myls
的玩具函数,它应该打印hello! 然后调用相同的内置函数Get-ChildItem
,内置别名ls
在参数行的其余部分完好无损的情况下调用该函数。 到目前为止我所拥有的效果很好:
function myls
{
Write-Output "hello!"
# $MyInvocation | Format-List # <-- uncomment this line for debug info
Invoke-Expression ("Get-ChildItem " + $MyInvocation.UnboundArguments -join " ")
}
正确版本的myls
应该能够处理不带参数、带一个参数、带命名参数、来自包含多个分号分隔命令的行以及参数中的变量(包括包含空格的字符串变量)的调用。 基本上,它应该是ls
替代品。
下面的测试比较了myls
和内置的ls
:
[注意:输出被省略和/或压缩以节省空间]
PS> md C:\p\d\x, C:\p\d\y, C:\p\d\"jay z"
PS> cd C:\p\d
PS> ls # no args
PS> myls # pass
PS> cd ..
PS> ls d # one arg
PS> myls d # pass
PS> $a="A"; $z="Z"; $y="y"; $jz="jay z"
PS> $a; ls d; $z # multiple statements
PS> $a; myls d; $z # pass
PS> $a; ls d -Exclude x; $z # named args
PS> $a; myls d -Exclude x; $z # pass
PS> $a; ls d -Exclude $y; $z # variables in arg-line
PS> $a; myls d -Exclude $y; $z # pass
PS> $a; ls d -Exclude $jz; $z # variables containing spaces in arg-line
PS> $a; myls d -Exclude $jz; $z # FAIL!
有没有办法可以重写myls
以获得我想要的行为?
简短回答:是的,这是可能的。 坏消息是:它需要知道参数的详细信息和关于希望调用的函数的其他元数据的代码。 好消息:你不需要自己写这一切。 此元数据可通过编程方式获得,并且存在可用于自动生成骨架代理代码的模块(请参阅下面的@Jaykul 的回答)。 我选择使用名为 "MetaProgramming" 的模块。 导入后,生成插入式myls
脚本非常简单:
New-ProxyCommand ls > .\\myls.ps1
然后可以开始自定义新生成的myls.ps1
脚本,如下所示:
...
begin
{
Write-Output "hello!" # <-- add this line
try {
$outBuffer = $null
...
瞧! 这个新版本通过了所有测试。
不幸的是,正确制作包装纸并不容易。 首先,splat 运算符大概应该应用于哈希表(例如自动PSBoundParameters
或其他),而不是直接应用于数组$args
。
至少有两个选项(都不完美)和一个 hack(参见更新部分)。
选项 1. 使用“经典”方式制作包装纸。 示例:查看函数help
是如何完成的,它是Get-Help
cmdlet 的包装器:
Get-Content function:\help
您可以看到包装函数声明了被包装 cmdlet 具有的所有参数,以便将PSBoundParameters
绑定到现有函数参数。
你的例子。 如果您的函数声明了参数Exclude
则示例代码开始工作。 但它仅适用于Exclude
,不适用于Force
,尽管Force
也传入:
function myls($Exclude) {
# only Exclude is in $PSBoundParameters even though we send Force, too:
$PSBoundParameters | Out-String | Out-Host
Write-Output "hello!"
Get-ChildItem @PSBoundParameters
}
cd d
myls -Exclude b -Force
选项 2。理论上应该可以从数组$args
手动构建一个哈希表并将 splat 运算符应用于它。 但这项任务实际上看起来并不吸引人。
更新
嗯,实际上还有另一个特别的选项(纯粹的 hack!),它需要最少的努力,并且可以在一些琐碎的、主要是交互式的场景中工作。 它不是为了某种严肃的代码!
function myls {
# extra job
Write-Output "hello!"
# invoke/repeat the calling code line with myls "replaced" with Get-ChildItem
Set-Alias myls Get-ChildItem
Invoke-Expression $MyInvocation.Line
}
cd d
# variables can be used as the parameter values, too
$exclude = 'b'
myls -Exclude $exclude -Force
如果您想要 ls 的嵌入式包装器,您应该编写一个适当的 Proxy Command 。 PoshCode.org 上有几个版本的生成器,包括Lee Holmes 的 PowerShell Cookbook 中的一个,
但是代理命令生成器现在是内置的,所以你可以只写:
$CommandName = "Get-ChildItem"
$Command = Get-Command $CommandName
[System.Management.Automation.ProxyCommand]::Create($Command)
我相信这一点:
函数 myls { 写输出“你好!”; iex "Get-ChildItem @args"}
将更接近产生预期的结果。
更新:以这种方式使用@args 传递命名参数显然存在一个已知错误:
我会停止使用它,直到它得到解决。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.