从Get-ChildItem -Path返回对象数组

3
从PowerShell中,ls -R *.txt会按目录递归列出文件,或者,更好的方法是:
PS> Get-ChildItem -Path C:\Test -Name

日志

anotherfile.txt
Command.txt
CreateTestFile.ps1
ReadOnlyFile.txt

但如何将其输入到数组中?我想要一个包含文件(?)对象本身的数组,查看以下内容: Get-ChildItem "C:\WINDOWS\System32" *.txt -Recurse | Select-Object FullName 参考链接:https://dev59.com/H2cs5IYBdhLWcg3wHwRH#24468733 我正在寻找使用PowerShell从这些类型命令中获取“文件”对象数组的方法。
可能更好的语法是: Copy-Item -Filter *.txt -Path c:\data -Recurse -Destination C:\temp\text 但是,与其复制项目不同,我只想要一个对象,或者说,一个对象数组。不是文件路径,不是文件,而是指向文件的PowerShell引用或指针。
(现在阅读精美手册。)

5
get-ChildItem "C:\windows\system32" -include "*.txt" -Recurse生成一个对象数组。请注意,我是中文语言模型,但我会尽力提供准确的翻译。 - AdminOfThings
4
我不确定你在这里的意图是什么。但是powershell会自动返回一个对象。你所要做的就是将其分配给一个变量。 $txtfiles = Get-ChildItem "C:\WINDOWS\System32" *.txt -Recurse | Select-Object FullName。在这种情况下,$txtfiles 将是一个数组对象。 - Sid
@AdminOfThings 这个数组将包含类型为 System.IO.FileSystemInfo 的对象?好的,这就是我需要知道的。 - Thufir
2个回答

8

简要概述:

  • 当你在 PowerShell 命令语句中将输出结果存储到变量中(例如,
    $output = Get-ChildItem ...),如果有两个或更多的输出对象,则自动将它们收集到数组中。

  • 为确保始终使用数组,即使只有一个或没有输出对象,可以使用 @(...)(例如,
    $output = @(Get-ChildItem ...)


  • PowerShell cmdlets,例如Get-ChildItem,可以输出任意数量的对象。

    • Get-ChildItem根据是否输出有关文件和/或目录的信息而输出[System.IO.FileInfo]和/或[System.IO.DirectoryInfo]对象。

    • 确定给定cmdlet的输出对象类型

      • 运行,例如,(Get-Command Get-ChildItem).OutputType
      • 如果不起作用,或者要查看特定调用输出的类型,请使用
        Get-ChildItem | Get-Member
      • Get-Help -Full Get-ChildItem还应显示一个OUTPUTS部分,如在线帮助中所示,但是在Get-ChildItem的情况下,它不太具体,因为Get-ChildItem也适用于文件系统之外的提供程序。
  • 输出到管道时,每个输出对象都会单独传递给管道中的下一个命令,通常立即进行处理。

  • 输出被捕获在一个变量中($var = ...时,以下逻辑适用:

    • 如果输出了两个或多个对象,则它们将被收集到一个常规的PowerShell数组中,该数组的类型为[object[]](即使实际元素具有特定类型)。
    • 如果输出一个对象,则按原样输出;也就是说,它不会被包装在数组中。
    • 如果没有输出任何对象,则输出一个“数组值空值”(有时称为其类型名称“AutomationNull”),在表达式上下文中的行为类似于$null,在枚举上下文中则像一个空集合;它不会产生可见输出-有关详情,请参见此答案

因此,当在变量中捕获时,给定命令可能根据情况返回:

  • 一组对象
  • 单个对象
  • “nothing”([System.Management.Automation.Internal.AutomationNull]::Value
为了确保给定命令的输出始终被视为数组,您有两个选择:
  • 使用@(...),即数组子表达式运算符;例如:
    • $fileSystemObjects = @(Get-ChildItem -Recurse -Filter *.txt)
  • 使用[array]对目标变量进行类型限制(等同于且更易于键入的[object[]])。
    • [array] $fileSystemObjects = Get-ChildItem -Recurse -Filter *.txt
但是,在PSv3+中,您通常不需要担心给定变量包含标量(单个值)还是数组,因为可以将标量隐式地视为数组:您可以即使在标量上调用.Count并使用索引([0][-1])。详情请参见此答案

好的,谢谢你关于如何处理类型和数组的指导。我喜欢 Get-Member 命令。 - Thufir
1
@Thufir,很高兴为您服务。您接受的答案告诉您Get-ChildItem返回的特定类型,这可能是您想要问的内容,但不是您实际提出的问题。请考虑未来读者的角度。 - mklement0
够公平了,我很感谢你详尽的回答。这个问题有点超出了我的能力范围,但我期望会多次回来看看它 :) - Thufir
1
简而言之,使用@(...)确保输出始终被视为数组! - xjcl
好的观点,@xjcl - 请看我的更新。 - mklement0

3

Get-ChildItem "C:\test" -Recurse将返回一个数组,其中包含FileInfo和DirectoryInfo对象

我们可以在这里看到一个展示示例:

Get-ChildItem "C:\test" -Recurse | %{
    $_.gettype()
}

返回结果
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     DirectoryInfo                            System.IO.FileSystemInfo
True     True     DirectoryInfo                            System.IO.FileSystemInfo
True     True     FileInfo                                 System.IO.FileSystemInfo
True     True     DirectoryInfo                            System.IO.FileSystemInfo

非常感谢,这正是我需要了解的。这是获取类型的标准习语吗? - Thufir
1
这个答案是误导性的,因为Get-ChildItem -Recurse有时不会返回一个数组。请参考mklement0的答案。 - orion elenzil
@orionelenzil 误导是一个强烈的词。他询问了一个问题,我给了他一个答案。我的答案适用于他想要的东西。他甚至在下面回复说谢谢,但是这对他来说“太深奥了”。有时候,并不总是需要或者想要深入的解释。 - ArcSet
我不确定。如果 c:\test 只包含一个文件,则结果类型为 System.IO.FileSystemInfo - orion elenzil
1
你可能是对的,“误导”这个词用得太过强烈了。我挑剔这个问题是因为这种特定的行为已经让我多次遇到麻烦——我编写的脚本针对返回许多文件的搜索运行良好,$x.Length等于项目数等等,但是当我的脚本在某个地方运行时,搜索只返回一个文件,现在我的代码就会出错。$x.Length是返回的单个文件的文件大小等等。 - orion elenzil
@orionelenzil 那是一个合理的担忧。好的 - ArcSet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接