有没有一种简单的方法可以确保返回的所有值都是True?在下面的示例中,我有一组表示文件的对象。我想在继续之前确保所有源文件都存在。我将所有路径传递给Test-Path,函数返回每个文件的True / False。
> $filesToUpdate = @(
[PsCustomObject] @{ Source = (Join-Path $basePath "Abc.module"); }
[PsCustomObject] @{ Source = (Join-Path $basePath "Def.module"); }
)
> $filesToUpdate.Source | Test-Path
True
True
> # How can I check if all the returned values are true?
如何检查所有返回的值是否为True?
答案 0 :(得分:3)
if (($filesToUpdate.Source | Test-Path) -contains $false){
#We know that one of the attempts was a failure
}
else{
#proceed
}
答案 1 :(得分:1)
PowerShell没有直接拥有任何类似LINQ的等价物(尽管有一些第三方模块可以为您提供这些功能)。
一般情况下,您只需过滤项目即可。如果内部有任何$false
值,则以下表达式将返回true-ish值:
$filesToUpdate.Source | Test-Path | ? { $_ -ne $true }
因此,当所有路径都存在时,为了得到“真”,你可以反转它:
!($filesToUpdate.Source | Test-Path | ? { $_ -ne $true })
或者,在您的具体情况下,您还可以将列表与Test-Path
:
$filesToUpdate.Source | ? { !(Test-Path $_) }
这为您提供了所有不存在的文件;当有任何不存在的文件时(即并非全部存在),最终会成为一个真实的值(你可以在条件中使用)。
答案 2 :(得分:1)
从管道使用的更广泛角度来对比和补充FoxDeploy's helpful answer和poke's answer:
<强> TL; DR:强>
(Test-Path $filesToUpdate.Source) -contains $false
:
Test-Path
接受数组作为输入并输出反映每个输入项存在的并行数组; -contains
测试LHS阵列中RHS标量的成员资格。 $filesToUpdate.Source | Test-Path | ? { $_ -ne $true } | Select-Object -First 1
? { $_ -ne $true }
按Test-Path
过滤布尔值输出,仅包含$false
值,如果有的话。因此,如果至少存在一个$false
值,则得到的集合将是非空的;非布尔集合在布尔上下文中使用时评估为$true
(无论其内容如何)。Select-Object -First 1
通过在收到第一个对象(第一个$false
值)后退出管道来优化[PSv3 +],但更重要的是确保只有单个值是回。
$false
)到无(无项目映射到$false
)。 通常,管道是PowerShell不可或缺的强大概念,即使它们引入了处理开销,它们也值得用于概念上的优雅,除非性能至关重要。
如果性能至关重要,那么管道可以解决,但这通常很麻烦。
在这个特定情况下,输入集合很小,基于数组的无管道解决方案在概念上更清晰和更快 - 巧合。/ > 在这种一般情况下使用管道的唯一原因是处理大量输入集合。
为了让您了解相对性能,这里有测试时间比较解决方案,参数化输入集合的大小和平均运行次数。
在底部找到测试脚本。
请注意,构造输入数据是为了将第一个(也是唯一的)不存在的路径放在输入集合的 middle 中。
此选择会显着影响Select-Object -First 1
解决方案的效果:
如果您改为在开头处放置一条不存在的路径,它将表现最佳,如果您将放在最后或者根本不包含一个,则不会有任何性能再次(相反)。
我机器上的样品编号(2012年末iMac),以秒为单位:
> .\Test.ps1 -count 10 -repeat 10 # 10 input items, timing averaged over 10 runs
Command 10-run average
------- --------------
-contains, no pipeline .00124
-contains, pipeline .00170
pipeline, where-object, select -first 1 .00276
pipeline, where-object .00314
pipeline, where-object, Test-Path in script block .00460
> .\Test.ps1 -count 100 -repeat 10
Command 10-run average
------- --------------
-contains, no pipeline .01190
pipeline, where-object, select -first 1 .01328
-contains, pipeline .01836
pipeline, where-object .02365
pipeline, where-object, Test-Path in script block .03725
> .\Test.ps1 -count 1000 -repeat 10
Command 10-run average
------- --------------
pipeline, where-object, select -first 1 .11154
-contains, no pipeline .11764
-contains, pipeline .16508
pipeline, where-object .22246
pipeline, where-object, Test-Path in script block .37015
> .\Test.ps1 -count 10000 -repeat 10
Command 10-run average
------- --------------
pipeline, where-object, select -first 1 1.09919
-contains, no pipeline 1.15089
-contains, pipeline 1.75926
pipeline, where-object 2.21868
pipeline, where-object, Test-Path in script block 3.65946
Test.ps1
param(
[int] $count = 50
,
[int] $repeat = 10
)
# Create sample input array.
$paths = @('c:') * $count
$paths[$paths.Count / 2] = 'nosuch'
$timingPropName = "$repeat-run average"
@(
[pscustomobject] @{ Command = "-contains, no pipeline"; $timingPropName =
(1..$($repeat) | % { (Measure-Command { (Test-Path $paths) -contains $false }).TotalSeconds } |
Measure-Object -average | % Average) }
[pscustomobject] @{ Command = "-contains, pipeline"; $timingPropName =
(1..$($repeat) | % { (Measure-Command { ($paths | Test-Path) -contains $false }).TotalSeconds } |
Measure-Object -average | % Average) }
[pscustomobject] @{ Command = "pipeline, where-object, select -first 1"; $timingPropName =
( 1..$($repeat) | % { (Measure-Command { $paths | Test-Path | ? { $_ -eq $false } | Select-Object -First 1 }).TotalSeconds } |
Measure-Object -average | % Average) }
[pscustomobject] @{ Command = "pipeline, where-object"; $timingPropName =
(1..$($repeat) | % { (Measure-Command { $paths | Test-Path | ? { $_ -eq $false } }).TotalSeconds } |
Measure-Object -average | % Average) }
[pscustomobject] @{ Command = "pipeline, where-object, Test-Path in script block"; $timingPropName =
(1..$($repeat) | % { (Measure-Command { $paths | ? { !(Test-Path $_) } }).TotalSeconds } |
Measure-Object -average | % Average) }
) |
Sort-Object $timingPropName |
Format-Table Command, @{ n=$timingPropName; e={ '{0:.00000}' -f $_.$timingPropName } }
答案 3 :(得分:0)
这是另一种方式,它具有“ and”功能,可对数组的所有元素执行“ -and”。
# foldright or reduce
function foldr ($sb, $accum, $list) {
if ($list.count -eq 0) { $accum }
else { & $sb $list[0] (foldr $sb $accum $list[1..$list.length]) }
}
function and ($list) {
foldr { $args[0] -and $args[1] } $true $list
}
$filestoupdate = [pscustomobject]@{source = $true,$true}
and $filestoupdate.source
True