我被困在一个学习项目上,我已经开始了,这里的目标是让我学习整个Begin
,Process
和End
块的概念
我的项目包含一个函数,它可以让用户打开一个具有特定配置文件的Firefox窗口,并可以通过保存在C:
驱动器上的.url
文件打开一个或多个网页。这是我目前掌握的情况:
Function Ask-Web{
[CmdletBinding()]
Param(
[Parameter(Position = 1)]
[ArgumentCompletions('andy','andrew','halley', "hanna")]
[Array]$FirefoxProfile = 'Andy',
[Parameter(ValueFromPipeline, Position = 2)]
[ArgumentCompletions('DIYhome','DIYreddit','DIYexchange','DIYall', 'SelectWithFZF')]
[Array]$Pages
)
Begin{
$FavouritePages = [ordered]@{
DIYhome = "https://www.diyUK.com"
DIYreddit = "https://www.reddit.com/r/DIY/submit"
DIYexchange = "https://diy.stackexchange.com/questions/ask"
# DIYall Will handle this later
}
[array]$Pages = If($Pages -eq "SelectWithFZF"){Get-ChildItem -Path "C:\temp\Ask Pages\" -Filter *.url*| FZF}Else{$FavouritePages."$Pages"} ;the FZF utility will store all selected items into $Pages variable
}
End{. 'C:\Program Files\Mozilla Firefox\firefox.exe' -p $FirefoxProfile $Pages}
}
该函数应该让用户通过参数完成来选择页面,从管道中预先提供网页,或者使用实用程序FZF从文件夹C:\temp\Ask Pages\
中进行选择。
在所有示例中,期望用户提供一个或多个页面/URL:
Ask-Web -FirefoxProfile andy -Pages DIYhome,DIYreddit,DIYexchange ; Open a singe Firefox window, with profile "Andy" and the pages DIYhome,DIYreddit and DIYexchange
Ask-Web -FirefoxProfile hanna -Pages DIYhome ; Open a singe Firefox window, with profile "Hanna" and the page DIYhome
Ask-Web -FirefoxProfile andrew -Pages SelectWithFZF ; Open a singe Firefox window, with profile "Andrew" and all the pages that were selected with FZF
Get-ChildItem .\Diy -filter *.url* | Ask-Web -FirefoxProfile hanna ; Open a singe Firefox window, with profile "Hanna" and with all the pages provided by the pipeline
我似乎被卡住的地方是让PowerShell一次给予我所有的管道输入,而不是一次一个或最后一个管道项,这就是我用上面的函数得到的。
如果我使用Process{. 'C:\Program Files\Mozilla Firefox\firefox.exe' -p $FirefoxProfile $Pages}
,那么PowerShell将为$Pages
中的每个项目打开一个Firefox窗口,而使用End{. 'C:\Program Files\Mozilla Firefox\firefox.exe' -p $FirefoxProfile $Pages}
,只有$Pages
中的最后一个项目被打开。
我试过:
Function Ask-Web{
[CmdletBinding()]
Param(
[Parameter(Position = 1)]
[ArgumentCompletions('andy','andrew','halley', "hanna")]
[Array]$FirefoxProfile = 'Andy',
[Parameter(ValueFromPipeline, Position = 2)]
[ArgumentCompletions('DIYhome','DIYreddit','DIYexchange','DIYall', 'SelectWithFZF')]
[Array]$Pages
)
Process{[Array]$Pages += @($input)}
End{$Pages}
}
对于Ask-Web -FirefoxProfile andy -Pages DIYhome,DIYreddit,DIYexchange
,在End
块中,我得到:
DIYhome
DIYreddit
DIYexchange
但是对于End
块中的'DIYhome','DIYreddit','DIYexchange'|Ask-Web -FirefoxProfile andy
,我得到:
DIYexchange
DIYexchange
如果我放弃所有Begin
、Process
和End
块:
Function Ask-Web{
[CmdletBinding()]
Param(
[Parameter(Position = 1)]
[ArgumentCompletions('andy','andrew','halley', "hanna")]
[Array]$FirefoxProfile = 'Andy',
[Parameter(ValueFromPipeline, Position = 2)]
[ArgumentCompletions('DIYhome','DIYreddit','DIYexchange','DIYall', 'SelectWithFZF')]
[Array]$Pages
)
$input
}
我得到了一致的结果,数组$Pages
的所有元素都被一次传递,不管用户如何提供它们。我怎么能做同样的,但与Begin
,Process
和End
块?
任何帮助将不胜感激!
2条答案
按热度按时间zfycwa2u1#
你有两个选择,推荐的一个是用
List<T>
收集通过管道的所有输入,这是在你的函数的process
块中完成的。然后在收集所有管道输入后,您可以在end
块中启动Firefox。使用
List<T>
而不是System.Array
(@()
和+=
)来收集管道输入的主要原因是因为数组的大小是固定的,并且PowerShell必须在每次添加新元素时重新创建它,这使得它非常低效。请参阅this answer和PowerShell脚本性能注意事项- Array addition以了解更多详细信息。在这种情况下,
List<T>
是必要的,因为PowerShell将通过管道一次传递一个对象,这就是所谓的一次一个处理。在这种情况下,不建议使用$input
,因为1.你的函数是一个advanced one,不建议在高级函数中使用这个自动变量。2.使用$input
意味着你的函数只能在管道中工作,除非你绕过它。第二个选项,也是不推荐的选项,是通过管道传递
Get-ChildItem
的结果,而不枚举它。为此,您可以使用Write-Output -NoEnumerate
或逗号运算符,
:k5ifujac2#
您的问题是您的
$Pages
变量存在作用域问题。当通过管道传递时,
$Pages
变量被重置为枚举的最新值。这就是为什么你只得到最后一个值两次。基本上,Process块每次都会看到一个新的$Pages
,所以在最后一轮中,您将添加最新的$input
。我认为最简单的解决方案是引入一个新变量,然后在End块中使用: