PowerShell相当于LINQ Any()? [英] PowerShell equivalent of LINQ Any()?

查看:71
本文介绍了PowerShell相当于LINQ Any()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从存储在Subversion中的脚本位置中找到所有顶级目录.

I would like to find all directories at the top level from the location of the script that are stored in subversion.

在C#中会是这样

Directory.GetDirectories(".")
  .Where(d=>Directories.GetDirectories(d)
     .Any(x => x == "_svn" || ".svn"));

在PowerShell中查找"Any()"的等效项时遇到了一些困难,并且我不想经历调用扩展方法的尴尬.

I'm having a bit of difficulty finding the equivalent of "Any()" in PowerShell, and I don't want to go through the awkwardness of calling the extension method.

到目前为止,我已经知道了:

So far I've got this:

 Get-ChildItem | ? {$_.PsIsContainer} | Get-ChildItem -force | ? {$_.PsIsContainer -and $_.Name -eq "_svn" -or $_.Name -eq ".svn"

这找到了我自己的svn目录,而不是它们的父目录-这就是我想要的.奖励积分,如果您能告诉我为什么添加

This finds me the svn directories themselves, but not their parent directories - which is what I want. Bonus points if you can tell me why adding

 | Select-Object {$_.Directory}

该命令列表的末尾仅显示一系列空行.

to the end of that command list simply displays a sequence of blank lines.

推荐答案

使用PowerShell v3 +解决方案回答立即问题:

To answer the immediate question with a PowerShell v3+ solution:

(Get-ChildItem -Force -Directory -Recurse -Depth 2 -Include '_svn', '.svn').Parent.FullName

-Directory将匹配限制为目录,-Recurse -Depth 2递归到三个级别(子代,孙代和曾孙代),Include允许指定多个(文件名组成部分)过滤器,而.Parent.FullName返回 parent 目录的完整路径.使用成员枚举(隐式访问集合的 elements'属性)来匹配匹配的目录.

-Directory limits the matches to directories, -Recurse -Depth 2 recurses up to three levels (children, grandchildren, and great-grandchildren), Include allows specifying multiple (filename-component) filters, and .Parent.FullName returns the full path of the parent dirs. of the matching dirs., using member enumeration (implicitly accessing a collection's elements' properties).

至于奖励问题:select-object {$_.Directory}不起作用, 因为 \[System.IO.DirectoryInfo\] Get-ChildItem返回的a>实例没有.Directory属性,只有.Parent属性; Select-Object -ExpandProperty Parent应该已经被使用.

As for the bonus question: select-object {$_.Directory} does not work, because the \[System.IO.DirectoryInfo\] instances returned by Get-ChildItem have no .Directory property, only a .Parent property; Select-Object -ExpandProperty Parent should have been used.

除了仅返回感兴趣的属性 value 外,-ExpandProperty还强制执行了该属性的存在.相比之下,假定输入对象没有.Directory属性,Select-Object {$_.Directory}返回一个自定义对象,该对象的文字名称为$_.Directory,其值为$null.这些$null值在控制台中显示为空行.

In addition to only returning the property value of interest, -ExpandProperty also enforces the existence of the property. By contrast, Select-Object {$_.Directory} returns a custom object with a property literally named $_.Directory, whose value is $null, given that the input objects have no .Directory property; these $null values print as empty lines in the console.

关于与

As for the more general question about a PowerShell equivalent to LINQ's .Any() method, which indicates [with a Boolean result] whether a given enumerable (collection) has any elements at all / any elements satisfying a given condition:

从本质上讲, PowerShell提供了 no 此类等效功能,但是可以模拟这种行为:

Natively, PowerShell offers no such equivalent, but the behavior can be emulated:

注意事项:此首先需要在内存中收集整个输入集合,这对于大型集合和/或长时间运行的输入命令可能会造成问题.

Caveat: This requires collecting the entire input collection in memory first, which can be problematic with large collections and/or long-running input commands.

(...).Where({ $_ ... }, 'First').Count -gt 0

...表示关注的命令,$_ ...表示关注的条件,应用于每个输入对象,其中PowerShell的自动$_变量引用当前的输入对象;参数'First'确保一旦找到第一个匹配项,该方法就返回.

... represents the command of interest, and $_ ... the condition of interest, applied to each input object, where PowerShell's automatic $_ variable refers to the input object at hand; argument 'First' ensures that the method returns once the first match has been found.

例如:

# See if there's at least one value > 1
PS> (1, 2, 3).Where({ $_ -gt 1 }, 'First').Count -gt 0
True


使用管道:测试命令是否产生了至少一个[符合条件]的输出对象:

基于管道的解决方案的优点是,它可以在正在生成的命令输出上逐个执行,而无需执行 首先将整个输出收集到内存中.


Using the pipeline: Testing whether a command produced at least one output object [matching a condition]:

The advantage of a pipeline-based solution is that it can act on a command's output one by one, as it is being produced, without needing to collect the entire output in memory first.

  • If you don't mind that all objects are enumerated - even if you only care if there is at least one - use Paolo Tedesco's helpful extension to JaredPar's helpful answer. The down-side of this approach is that you always have to wait for a (potentially long-running) command to finish producing all output objects, even though - logically - the determination whether there are any output objects can be made as soon as the first object is received.

如果您想在遇到一个 [matching]对象后立即退出管道 ,则有两个选择:

If you want to exit the pipeline as soon as one [matching] object has been encountered, you have two options:

  • [即席:易于理解,但实施起来很麻烦] 用 dummy循环封闭管道,并使用break中断管道,然后该循环(...代表要测试其输出的命令,而符合条件):

  • [Ad-hoc: Easy to understand, but cumbersome to implement] Enclose the pipeline in a dummy loop and use break to break out of the pipeline and that loop (... represents the command whose output to test, and $_ ... match the condition):

 # Exit on first input object.
 [bool] $haveAny = do { ... | % { $true; break } } while ($false)

 # Exit on first input object that matches a condition.
 [bool] $haveAny = do { ... | % { if ($_ ...) { $true ; break } } } while ($false)

  • [使用实现起来很简单的PowerShell v3 +自包含实用程序功能] 请参见下面的功能Test-Any 的实现. 可以将其添加到脚本中,或在交互式会话中使用,添加到您的$PROFILE文件中.

  • [Use a PowerShell v3+ self-contained utility function that is nontrivial to implement] See the implementation of function Test-Any below. It can be added to scripts or, for use in interactive sessions, to your $PROFILE file.

    该功能非常重要,因为从Windows PowerShell v5.1,PowerShell Core v6开始,没有 direct 方法过早退出管道,因此基于变通办法在.NET反射上,目前需要私有类型.

    The function is nontrivial, because as of Windows PowerShell v5.1, PowerShell Core v6, there is no direct way to exit a pipeline prematurely, so a workaround based on .NET reflection and a private type is currently necessary.

    如果您同意应该有这样的功能,请参加GitHub上的对话 a>.

    If you agree that there should be such a feature, take part in the conversation on GitHub.

    #requires -version 3
    Function Test-Any {
    
        [CmdletBinding()]
        param(
            [ScriptBlock] $Filter,
            [Parameter(ValueFromPipeline = $true)] $InputObject
        )
    
        process {
          if (-not $Filter -or (Foreach-Object $Filter -InputObject $InputObject)) {
              $true # Signal that at least 1 [matching] object was found
              # Now that we have our result, stop the upstream commands in the
              # pipeline so that they don't create more, no-longer-needed input.
              (Add-Type -Passthru -TypeDefinition '
                using System.Management.Automation;
                namespace net.same2u.PowerShell {
                  public static class CustomPipelineStopper {
                    public static void Stop(Cmdlet cmdlet) {
                      throw (System.Exception) System.Activator.CreateInstance(typeof(Cmdlet).Assembly.GetType("System.Management.Automation.StopUpstreamCommandsException"), cmdlet);
                    }
                  }
                }')::Stop($PSCmdlet)
          }
        }
        end { $false }
    }
    

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆