如何检查所有返回的值是否为真?

时间:2016-07-11 18:13:26

标签: powershell

有没有一种简单的方法可以确保返回的所有值都是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?

4 个答案:

答案 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 answerpoke'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