首先,制作一些示例文件:
2010..2015 | % { "" | Set-Content "example $_.txt" }
#example 2010.txt
#example 2011.txt
#example 2012.txt
#example 2013.txt
#example 2014.txt
#example 2015.txt
Run Code Online (Sandbox Code Playgroud)
我想要做的是将年份与正则表达式捕获组匹配,然后引用匹配$matches[1]并使用它.我可以写这个在一个scriptblock中,在一个cmdlet中执行,并且它工作正常:
gci *.txt | foreach {
if ($_ -match '(\d+)') # regex match the year
{ # on the current loop variable
$matches[1] # and use the capture group immediately
}
}
#2010
#2011
#.. etc
Run Code Online (Sandbox Code Playgroud)
我也可以写这个来在一个scriptblock中进行匹配,然后$matches在另一个cmdlet的scriptblock中引用:
gci *.txt | where {
$_ -match '(\d+)' # regex match here, in the Where scriptblock
} | foreach { # pipeline!
$matches[1] # use $matches which was set in the previous
# scriptblock, in a different cmdlet
}
Run Code Online (Sandbox Code Playgroud)
它具有相同的输出,似乎工作正常.但它是否有保证可行,或者它是不确定的和巧合的?
可以'example 2012.txt'匹配,然后缓冲.'example 2013.txt'匹配,然后缓冲.| foreach开始工作,'example 2012.txt'但$matches已经更新,2013他们不同步?
我不能让它们失去同步 - 但我仍然可以依赖于未定义的行为.
(FWIW,我更喜欢清晰度和可读性的第一种方法).
本身没有同步.第二个例子是有效的,因为管道的工作方式.当每个单个对象通过满足条件传递时Where-Object,该-Process块ForEach-Object立即处理它,因此$Matches尚未被任何其他-match操作覆盖.
如果你要做的事情导致管道在传递它们之前收集对象,比如排序,你就会遇到麻烦:
gci *.txt | where {
$_ -match '(\d+)' # regex match here, in the Where scriptblock
} | sort | foreach { # pipeline!
$matches[1] # use $matches which was set in the previous
# scriptblock, in a different cmdlet
}
Run Code Online (Sandbox Code Playgroud)
例如,上面应该失败,输出n个对象,但它们都将是最后一个匹配.
所以谨慎不要依赖它,因为它掩盖了危险.其他人(或者你几个月后)可能不会想到任何插入a sort然后对结果感到困惑.
正如TheMadTechnician在评论中指出的那样,这个位置会改变一些事情.将排序放在您引用的部分之后$Matches(在foreach)中,或在过滤之前where,它仍将按预期工作.
我认为这应该避免这一点,因为它还不太清楚.如果代码在您无法控制的部分管道中发生更改,则行为可能会意外地变为不同.
我喜欢抛出一些详细的输出来证明这一点:
gci *.txt | where {
"Where-Object: $_" | Write-Verbose -Verbose
$_ -match '(\d+)' # regex match here, in the Where scriptblock
} | foreach { # pipeline!
"ForEach-Object: $_" | Write-Verbose -Verbose
$matches[1] # use $matches which was set in the previous
# scriptblock, in a different cmdlet
}
Run Code Online (Sandbox Code Playgroud)
gci *.txt | where {
"Where-Object: $_" | Write-Verbose -Verbose
$_ -match '(\d+)' # regex match here, in the Where scriptblock
} | sort | foreach { # pipeline!
"ForEach-Object: $_" | Write-Verbose -Verbose
$matches[1] # use $matches which was set in the previous
# scriptblock, in a different cmdlet
}
Run Code Online (Sandbox Code Playgroud)
你会看到的不同之处在于,在原版中,只要where"清除"一个对象,立即foreach获取它.在排序中,您可以where在foreach获取任何内容之前先查看所有发生的事情.
sort没有任何冗长的输出,所以我不打扰那样调用它,但基本上它的Process {}块只是收集所有对象,所以它可以比较(排序!)它们,然后在End {}块中吐出它们.
首先,这是一个模拟Sort-Object对象集合的函数(它实际上不对它们进行排序或执行任何操作):
function mocksort {
[CmdletBinding()]
param(
[Parameter(
ValueFromPipeline
)]
[Object]
$O
)
Begin {
Write-Verbose "Begin (mocksort)"
$objects = @()
}
Process {
Write-Verbose "Process (mocksort): $O (nothing passed, collecting...)"
$objects += $O
}
End {
Write-Verbose "End (mocksort): returning objects"
$objects
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我们可以使用前面的示例,最后一些睡眠:
gci *.txt | where {
"Where-Object: $_" | Write-Verbose -Verbose
$_ -match '(\d+)' # regex match here, in the Where scriptblock
} | mocksort -Verbose | foreach { # pipeline!
"ForEach-Object: $_" | Write-Verbose -Verbose
$matches[1] # use $matches which was set in the previous
# scriptblock, in a different cmdlet
} | % { sleep -milli 500 ; $_ }
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
680 次 |
| 最近记录: |