下面的代码给了我一个 PSCustomObjects 数组,我怎样才能让它返回一个字符串数组?
$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)}
(作为第二个问题,psiscontainer 部分是做什么用的?我从网上的一个例子中复制了它)
接受后编辑:两个很好的答案,希望我能同时标记它们。已授予原始答案。
下面的代码给了我一个 PSCustomObjects 数组,我怎样才能让它返回一个字符串数组?
$files = Get-ChildItem $directory -Recurse | Select-Object FullName | Where-Object {!($_.psiscontainer)}
(作为第二个问题,psiscontainer 部分是做什么用的?我从网上的一个例子中复制了它)
接受后编辑:两个很好的答案,希望我能同时标记它们。已授予原始答案。
您只需要从对象中挑选出您想要的属性。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}
请注意,其中一个值正在被变量捕获。它不会出现在输出管道中。
要获取文件名的字符串,您可以使用
$files = Get-ChildItem $directory -Recurse | Where-Object {!($_.psiscontainer)} | Select-Object -ExpandProperty FullName
该-ExpandProperty
参数允许您根据指定的属性类型取回对象。
进一步的测试表明,这不适用于 V1,但该功能自 V2 CTP3 起已修复。
对于问题 #1
我已经删除了“select-object”部分 - 它是多余的,并且在“foreach”之前移动了“where”过滤器,这与dangph 的答案不同- 尽快过滤,以便您只处理下一个必须处理的子集管道。
$files = Get-ChildItem $directory -Recurse | Where-Object {!$_.PsIsContainer} | foreach {$_.FullName}
该代码片段基本上读取
请注意,对于foreach {$_.FullName},在 powershell 中,将返回脚本块 ({...}) 中的最后一条语句,在本例中为 $_.FullName 类型的字符串
如果你真的需要得到一个原始对象,你不需要在摆脱“select-object”之后做任何事情。如果您要使用 Select-Object 但想要访问原始对象,请使用“PsBase”,这是一个完全不同的问题(主题) - 请参阅“ PSBASE、PSEXTENDED、PSADAPTED 和 PSOBJECT 有什么问题? ”了解更多信息那个主题
对于问题 #2
并且通过!$_.PsIsContainer过滤意味着您排除了容器级别的对象 - 在您的情况下,您正在对FileSystem提供程序执行Get-ChildItem(您可以通过 Get-PsProvider 查看 PowerShell 提供程序),因此容器是目录信息(文件夹)
PsIsContainer在不同的 PowerShell 提供者下意味着不同的东西;例如)对于注册表提供程序,PsIsContainer 的类型是Microsoft.Win32.RegistryKey 试试这个:
>pushd HKLM:\SOFTWARE
>ls | gm
[更新]以下问题:foreach 做什么?这是在枚举什么? 为了澄清,“foreach”是“Foreach-Object”的别名你可以通过以下方式找到,
get-help foreach
- 或者 -
get-alias foreach
现在在我的回答中,“foreach”正在枚举从前一个管道(已过滤目录)返回 的FileInfo类型的每个对象实例。FileInfo有一个名为FullName的属性,这就是“foreach”正在枚举的内容。
并且您通过名为“$_”的特殊管道变量引用通过管道传递的对象,该变量在“foreach”的脚本块上下文中属于FileInfo类型。
对于 V1,将以下过滤器添加到您的配置文件中:
filter Get-PropertyValue([string]$name) { $_.$name }
然后你可以这样做:
gci . -r | ?{!$_.psiscontainer} | Get-PropertyName fullname
顺便说一句,如果您使用的是PowerShell 社区扩展,那么您已经拥有它。
关于在 V2 中使用 Select-Object -Expand 的能力,这是一个可爱的技巧,但并不明显,而且真的不是 Select-Object 和 -Expand 的本意。-Expand 与 LINQ 的 SelectMany 一样是关于展平的,而 Select-Object 则是关于将多个属性投影到自定义对象上。