我想从subversion中存储的脚本位置找到顶层的所有目录。
在C#中它会是这样的
Directory.GetDirectories(".")
.Where(d=>Directories.GetDirectories(d)
.Any(x => x == "_svn" || ".svn"));
我在PowerShell中找到相当于“Any()”的方法有点困难,而且我不想经历调用扩展方法的尴尬。
到目前为止,我已经得到了这个:
Get-ChildItem | ? {$_.PsIsContainer} | Get-ChildItem -force | ? {$_.PsIsContainer -and $_.Name -eq "_svn" -or $_.Name -eq ".svn"
这找到了svn
目录本身,但不是它们的父目录 - 这就是我想要的。如果你能告诉我添加
| Select-Object {$_.Directory}
到该命令列表的末尾只显示一系列空行。
答案 0 :(得分:22)
不幸的是,PowerShell中没有相应的功能。我写了一篇关于此的博客文章,建议使用通用的Test-Any函数/过滤器。
function Test-Any() {
begin {
$any = $false
}
process {
$any = $true
}
end {
$any
}
}
答案 1 :(得分:16)
@ JaredPar答案的变体,将测试纳入Test-Any
过滤器:
function Test-Any {
[CmdletBinding()]
param($EvaluateCondition,
[Parameter(ValueFromPipeline = $true)] $ObjectToTest)
begin {
$any = $false
}
process {
if (-not $any -and (& $EvaluateCondition $ObjectToTest)) {
$any = $true
}
}
end {
$any
}
}
现在我可以编写“任何”测试,例如
> 1..4 | Test-Any { $_ -gt 3 }
True
> 1..4 | Test-Any { $_ -gt 5 }
False
答案 2 :(得分:8)
您可以使用原始LINQ Any
:
[Linq.Enumerable]::Any($list)
答案 3 :(得分:5)
我现在的做法是:
gci -r -force `
| ? { $_.PSIsContainer -and $_.Name -match "^[._]svn$" } `
| select Parent -Unique
原因
select-object {$_.Directory}
没有返回任何有用的东西,因为DirectoryInfo
对象上没有这样的属性。至少不在我的PowerShell中。
详细说明您自己的答案:PowerShell可以将大多数非空集合视为$true
,因此您只需执行以下操作:
$svnDirs = gci `
| ? {$_.PsIsContainer} `
| ? {
gci $_.Name -Force `
| ? {$_.PSIsContainer -and ($_.Name -eq "_svn" -or $_.Name -eq ".svn") }
}
答案 4 :(得分:4)
实际上非常简单 - 只需先选择$ true(为清晰起见而格式化):
[bool] ($source `
| foreach { [bool] (<predicate>) } `
| where { $_ } `
| select -first 1)
替代方式:
($source `
| where { <predicate> } `
| foreach { $true } `
| select -first 1)
答案 5 :(得分:3)
我最终用计数来做这件事:
$directoryContainsSvn = {
(Get-ChildItem $_.Name -force | ? {$_.PsIsContainer -and $_.Name -eq "_svn" -or $_.Name -eq ".svn"} | Measure-Object).Count -eq 1
}
$svnDirs = Get-ChildItem | ? {$_.PsIsContainer} | ? $directoryContainsSvn
答案 6 :(得分:2)
你可以稍微收紧一下:
gci -fo | ?{$_.PSIsContainer -and `
(gci $_ -r -fo | ?{$_.PSIsContainer -and $_ -match '[_.]svn$'})}
注意 - 将$ __。名称传递给嵌套的gci是不必要的。通过它$ _就足够了。
答案 7 :(得分:1)
我推荐以下解决方案:
<#
.SYNOPSIS
Tests if any object in an array matches the expression
.EXAMPLE
@( "red", "blue" ) | Where-Any { $_ -eq "blue" } | Write-Host
#>
function Where-Any
{
[CmdletBinding()]
param(
[Parameter(Mandatory = $True)]
$Condition,
[Parameter(Mandatory = $True, ValueFromPipeline = $True)]
$Item
)
begin {
[bool]$isMatch = $False
}
process {
if (& $Condition $Item) {
[bool]$isMatch = $true
}
}
end {
Write-Output $isMatch
}
}
# optional alias
New-Alias any Where-Any
答案 8 :(得分:1)
这是我到目前为止找到的最好的方法(如果已经找到了true,则不会迭代所有元素,并且不会破坏管道):
来自 LINQ Any() equivalent in PowerShell
可以在函数范围内使用包含整个管道的内置$ input变量。
因此,所需的代码可能如下所示:
function Test-Any([scriptBlock] $scriptBlock = {$true}, [scriptBlock] $debugOut = $null)
{
if ($debugOut)
{
Write-Host(“{0} | % {{{1}}}” -f $input, $scriptBlock)
}
$_ret = $false;
$_input = ($input -as [Collections.IEnumerator])
if ($_input)
{
while ($_input.MoveNext())
{
$_ = $_input.Current;
Write-Host $_
if ($debugOut)
{
Write-Host(“Tested: [{0}]” -f (&$debugOut))
}
if (&$scriptBlock)
{
if ($debugOut)
{
Write-Host(“Matched: [{0}]” -f (&$debugOut))
}
$_ret = $true
break
}
}
}
$_ret
}
答案 9 :(得分:1)
我认为这里最好的答案是@JaredPar提出的功能,但如果你像我一样喜欢单行,我想提议 Any
单行 :
# Any item is greater than 5
$result = $arr | %{ $match = $false }{ $match = $match -or $_ -gt 5 }{ $match }
%{ $match = $false }{ $match = $match -or YOUR_CONDITION }{ $match }
检查至少一个项目匹配条件。
一个注意事项 - 通常 Any 操作会对数组进行求值,直到找到匹配条件的第一个项目为止。但此代码会评估所有项目。
简而言之,您可以轻松将其调整为 All
单行:
# All items are greater than zero
$result = $arr | %{ $match = $false }{ $match = $match -and $_ -gt 0 }{ $match }
%{ $match = $false }{ $match = $match -and YOUR_CONDITION }{ $match }
检查所有项目是否符合条件。
注意,要检查您需要的任何-or
并选中所有您需要的-and
。
答案 10 :(得分:0)
我采用了更 linq 风格的方法。
我知道这个问题可能很老了。我用它来满足我的需求:
PS> $searchData = "unn"
PS> $StringData = @("unn", "dew", "tri", "peswar", "pymp")
PS> $delegate = [Func[string,bool]]{ param($d); return $d -eq $searchData }
PS> [Linq.Enumerable]::Any([string[]]$StringData, $delegate)
取自此处: