【问题标题】:How to get Select-Object to return a raw type (e.g. String) rather than PSCustomObject?如何让 Select-Object 返回原始类型(例如字符串)而不是 PSCustomObject?
【发布时间】:2010-10-11 18:00:28
【问题描述】:

下面的代码给了我一个 PSCustomObjects 数组,我怎样才能让它返回一个字符串数组?

$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)}

(作为第二个问题,psiscontainer 部分是做什么用的?我从网上的一个示例中复制了它)

接受后编辑:两个很好的答案,希望我能同时标记它们。已授予原始答案。

【问题讨论】:

    标签: powershell pscustomobject


    【解决方案1】:

    您只需要从对象中挑选出您想要的属性。 FullName 在这种情况下。

    $files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)} | foreach {$_.FullName}
    

    编辑: 对 Mark 的解释,他问道:“foreach 是做什么的?枚举是什么?”

    Sung Meister 的解释非常好,但我会在这里添加一个演练,因为它可能会有所帮助。

    关键概念是管道。想象一系列乒乓球一个接一个地滚下一个狭窄的管子。这些是管道中的对象。管道的每个阶段——由管道 (|) 字符分隔的代码段——都有一个管道进入它,管道从它流出。一个阶段的输出连接到下一个阶段的输入。每个阶段都会在对象到达时对其进行处理,然后将它们发送回输出管道或发送新的替换对象。

    Get-ChildItem $directory -Recurse
    

    Get-ChildItem 遍历文件系统,创建代表它遇到的每个文件和目录的 FileSystemInfo 对象,并将它们放入管道中。

    Select-Object FullName
    

    Select-Object 在每个 FileSystemInfo 对象到达时获取它,从中获取 FullName 属性(在本例中为路径),将该属性放入它创建的全新自定义对象中,然后将该自定义对象放入管道。

    Where-Object {!($_.psiscontainer)}
    

    这是一个过滤器。它获取每个对象,对其进行检查,然后根据某些条件将其送回或丢弃。顺便说一句,您这里的代码有一个错误。到达这里的自定义对象没有 psiscontainer 属性。这个阶段实际上并没有做任何事情。 Sung Meister 的代码更好。

    foreach {$_.FullName}
    

    Foreach,其长名称是 ForEach-Object,在每个对象到达时抓取它,在这里,从它抓取 FullName 属性,一个字符串。现在,这里是微妙的部分:任何未被消耗的值,即未被变量捕获或以某种方式抑制的值,都被放入输出管道。作为一个实验,尝试用这个替换那个阶段:

    foreach {'hello'; $_.FullName; 1; 2; 3}
    

    实际尝试一下并检查输出。该代码块中有四个值。它们都没有被消耗。请注意,它们都出现在输出中。现在试试这个:

    foreach {'hello'; $_.FullName; $ x = 1; 2; 3}
    

    请注意,其中一个值正在被变量捕获。它不会出现在输出管道中。

    【讨论】:

    • 更好的解决方案是使用 select-object -expand FullName
    • 仅供参考,您可以使用tee-object 分配给变量 发送到输出。示例:ls | select -first 1 -property fullname | %{$_.FullName} | tee -variable firstpath
    【解决方案2】:

    要获取文件名的字符串,您可以使用

    $files = Get-ChildItem $directory -Recurse | Where-Object {!($_.psiscontainer)} | Select-Object -ExpandProperty FullName
    

    -ExpandProperty 参数允许您根据指定属性的类型取回一个对象。

    进一步的测试表明,这不适用于 V1,但该功能自 V2 CTP3 起已修复。

    【讨论】:

      【解决方案3】:

      对于问题 #1

      我已经删除了“select-object”部分 - 它是多余的,并且在“foreach”之前移动了“where”过滤器,这与 dangph's answer 不同 - 尽快过滤,以便您只处理必须处理的子集在下一条管道中。

      $files = Get-ChildItem $directory -Recurse | Where-Object {!$_.PsIsContainer} | foreach {$_.FullName}
      

      代码 sn-p 本质上是这样的

      • 递归获取所有文件的完整路径(Get-ChildItem $directory -Recurse)
      • 过滤掉目录(Where-Object {!$_.PsIsContainer})
      • 仅返回完整文件名(foreach {$_.FullName})
      • 将所有文件名保存到 $files

      请注意,对于 foreach {$_.FullName},在 powershell 中,返回脚本块 ({...}) 中的最后一条语句,在本例中为字符串类型的 $_.FullName

      如果你真的需要得到一个原始对象,你不需要在摆脱“select-object”之后做任何事情。如果您要使用 Select-Object 但想访问原始对象,请使用“PsBase”,这是一个完全不同的问题(主题) - 有关该主题的更多信息,请参阅“What's up with PSBASE, PSEXTENDED, PSADAPTED, and PSOBJECT?

      关于问题 #2

      并且还通过 !$_.PsIsContainer 过滤意味着您排除了容器级别的对象 - 在您的情况下,您正在 Get-ChildItem 上执行 >FileSystem提供者(通过Get-PsProvider可以看到PowerShell提供者),所以容器是DirectoryInfo(文件夹)

      PsIsContainer 在不同的 PowerShell 提供者下表示不同的东西; 例如)对于 Registry 提供者,PsIsContainer 的类型为 Microsoft.Win32.RegistryKey 试试这个:

      >pushd HKLM:\SOFTWARE
      >ls | gm
      

      [UPDATE] 回答以下问题:foreach 是做什么的?枚举是什么? 澄清一下,“foreach”是“Foreach-Object”的别名 你可以通过了解,

      get-help foreach
      

      -- 或--

      get-alias foreach
      

      现在在我的回答中,“foreach”正在枚举从前一个管道(已过滤目录)返回的 FileInfo 类型的每个对象实例。 FileInfo 有一个名为 FullName 的属性,这就是“foreach”正在枚举的内容。
      并且您通过名为“$_”的特殊管道变量引用通过管道传递的对象,该变量在“foreach”的脚本块上下文中属于 FileInfo 类型。

      【讨论】:

      • foreach 是做什么的?枚举是什么?
      【解决方案4】:

      对于 V1,将以下过滤器添加到您的个人资料中:

      filter Get-PropertyValue([string]$name) { $_.$name }
      

      那么你可以这样做:

      gci . -r | ?{!$_.psiscontainer} | Get-PropertyName fullname
      

      顺便说一句,如果您使用的是PowerShell Community Extensions,那么您已经有了它。

      关于在 V2 中使用 Select-Object -Expand 的能力,这是一个可爱的技巧,但并不明显,而且真的不是 Select-Object 和 -Expand 的本意。 -Expand 与 LINQ 的 SelectMany 一样是关于展平的,而 Select-Object 则是关于将多个属性投影到自定义对象上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-27
        • 2021-07-12
        • 1970-01-01
        • 2014-07-11
        • 1970-01-01
        • 2016-03-19
        • 1970-01-01
        • 2012-08-25
        相关资源
        最近更新 更多