【问题标题】:Get-ChildItem -Exclude returning Fullname instead of short nameGet-ChildItem - 排除返回全名而不是短名
【发布时间】:2015-06-01 02:20:17
【问题描述】:

我在运行 Get-ChildItem -Exclude 时遇到了一个奇怪的问题。

在运行副本然后比较两个目录之后,我一直在源位置和目标位置使用以下命令来创建文件数组。它一直工作得很好。 (本来想发图片的,但是知名度不够高)

$sourcefiles = @(Get-ChildItem -Recurse -path e:\Home\o365.test)

当我运行此命令时,数组会填充文件的短名称。

我从文件副本中排除了 PST 文件,并且我还需要在比较中排除它们,因此我在 GCI 命令中添加了排除。

$sourcefiles = @(Get-ChildItem -Recurse -path e:\Home\o365.test -Exclude *.pst)

这会返回所有正确的文件(*.pst 实际上不包括在内),但是它会返回文件的全名,而不是我之前总是返回的短名。

这会导致比较对象失败,因为目标 GCI 没有排除项(不需要,因为 *.pst 已从副本中排除)。此外,它是一个 UNC 路径,而且全名也不匹配。

我意识到我可以使用 split-path -leaf(我已经尝试过 - 并且似乎有效)

$sourcefiles = @(Get-ChildItem -Recurse -path e:\Home\o365.test -Exclude *.pst | Split-Path -Leaf) 

但我仍然不明白为什么将 -exclude 参数添加到 GCI 会导致它改变它返回的格式。

有没有人知道为什么会发生这种情况?

提前感谢您的帮助!

【问题讨论】:

  • 对于像我这样在搜索“短名称”后到达这里的人来说,OP 似乎使用“短名称”来表示其目录中的文件名(“文件名”)和“长名称”表示完整路径规范(“文件路径”)。术语“短名称”通常用于指代 DOS 兼容的 8.3 备用文件名,它可以链接到某些文件系统上的同一文件(或目录)(例如,始终在 FAT32 和 NTFS 上,除非在以下情况下设置了 disable8dot3 标志)文件已创建)。

标签: powershell powershell-3.0


【解决方案1】:

好吧,我无法复制您在此处看到的内容。在 PowerShell 中的操作之前放置一个 at 符号实际上是数组运算符,简单地将它放在带有操作的括号之前不会像您描述的那样返回单个属性。

现在,如果您将属性名称放在括号后面以仅选择一个属性,则可以实现此目的。例如:

$files = @(Get-ChildItem -path c:\temp).BaseName
>LZelda.csv
>msvcr100.dll
>names-0.txt
>names-1.txt
>NOBGW00017.log
>nslookup.exe
>PolicySpy.exe

添加 -Exclude 括号根本不会改变输出。

$files = @(Get-ChildItem -path c:\temp -exclude *.png)
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        3/18/2015   2:34 PM                Android
da----        9/10/2013   7:17 PM                Bootfiles
d-----       12/13/2014   4:29 PM                camera
d-----         1/6/2015  11:49 AM                CFS
d-----       12/11/2014   1:08 PM                ebay
d-----         2/2/2014   1:55 PM                Finance

我向您展示这一点的原因是我们返回的东西仍然是 FileSystem 对象。将 $files 减少到仅包含一个属性的唯一方法,例如 FullName、BaseName 或以下两种方法中的任何内容:

$files = @(Get-ChildItem -path c:\temp -exclude *.png).BaseName
$files = @(Get-ChildItem -path c:\temp -exclude *.png | Select -Expand BaseName)

两者都会给出相同的输出。

【讨论】:

  • 感谢狐狸的回复。我意识到我正在创建一个数组。我实际上是在比较对象,而不仅仅是名称。问题仅出在一个属性上 - 项目的名称,但由于每种情况下的名称不同,因此比较失败。
  • 也许您的意思是“名称”属性。 “basename”(脚本属性)是删除了任何扩展名的名称。因此,第一个示例应该是删除了扩展名(.csv、.dll、.txt、.log、.exe)的文件列表。 (除非在这些被删除之后有进一步的扩展。)
【解决方案2】:

这里的问题是从 Powershell 开始(或至少从 PS2.0 开始)引入的故意“错误”(我称之为)。为了简化从 cmd 到 Powershell 的转换,Get-ChildItem 被赋予别名 dir,然后使其像 dircmd 版本一样工作(尽可能提供类似外观的输出)。和cmd一样,

PS > dir <directory path>

产生 的列表(当简单显示时)。在这两种情况下(cmd 和 Powershell),缺少的目录路径使用 . (当前目录)。但是,如果 cmd 版本在目录路径之后使用文件名或通配符模式调用(同样,如果没有目录路径,则为隐含的 .),则输出是匹配的文件(以及通配符大小写的目录)该目录(如果有)。 Get-ChildItem 执行相同的操作,因此别名 dir 提供类似的输出。可能已经预料到Get-ChildItem 在提供通配符路径时会返回与该通配符路径匹配的任何目录的children 列表并忽略任何匹配的文件。如果参数是纯文件名,Get-ChildItem 会抱怨提供的参数不能有子级(与 可以 有子级但没有子级的空目录相反)。毕竟,如果你想匹配文件或目录本身(而不是它们的内容),你会使用Get-Item。实际上,Get-ChildItem 在文件参数和通配符的情况下返回的结果与等效的Get-Item 相同。但是,Get-ChildItem 为指定目录路径的实际子级返回的结果与Get-Item 的结果略有不同。具体来说,它们有不同的 ToString() 方法(即使它们都返回 FileInfo 或 DirectoryInfo 对象)。这意味着通过显式调用ToString() 或在需要字符串的表达式中使用返回的对象,例如

将对象转换为字符串
PS > dir | foreach { "$_" }

给出不同的结果。 示范,

PS > gci C:\Windows\Web\Screen | foreach { "$_" }
img100.jpg
img101.png
img102.jpg
img103.png
img104.jpg
img105.jpg
PS > gci C:\Windows\web\screen\* | foreach { "$_" }
C:\Windows\web\screen\img100.jpg # note: uses argument path case.
C:\Windows\web\screen\img101.png # actual directory path case is
C:\Windows\web\screen\img102.jpg # C:\WINDOWS\Web\Screen
C:\Windows\web\screen\img103.png
C:\Windows\web\screen\img104.jpg
C:\Windows\web\screen\img105.jpg
PS > gi C:\Windows\Web\screen\* | foreach { "$_" }
C:\Windows\Web\screen\img100.jpg
C:\Windows\Web\screen\img101.png
C:\Windows\Web\screen\img102.jpg
C:\Windows\Web\screen\img103.png
C:\Windows\Web\screen\img104.jpg
C:\Windows\Web\screen\img105.jpg
PS > gci C:\Windows\Web\screen\img100.jpg | foreach { "$_" }
C:\Windows\Web\screen\img100.jpg
PS > gi C:\Windows\Web\screen\img100.jpg | foreach { "$_" }
C:\Windows\Web\screen\img100.jpg

因此,我怀疑 OP 正在使用隐式字符串转换来获取文件的“名称”并运行此“错误”的犯规,这显然在使用 -Exclude 时也会表现出来(独立于 -Recurse 有没有效果)。解决方案是不依赖字符串转换并使用实际的字符串属性,名称或全名(无论需要哪个)。

PS > gci C:\Windows\Web\Screen | foreach { "$($_.fullname)" }
C:\Windows\Web\screen\img100.jpg
C:\Windows\Web\screen\img101.png
C:\Windows\Web\screen\img102.jpg
C:\Windows\Web\screen\img103.png
C:\Windows\Web\screen\img104.jpg
C:\Windows\Web\screen\img105.jpg
PS > gci C:\Windows\web\screen\* | foreach { "$($_.name)" }
img100.jpg
img101.png
img102.jpg
img103.png
img104.jpg
img105.jpg

另一种(长期)解决方案可能是修复Get-ChildItem,以便ToString() 始终返回相同的结果。这可能被认为是一个重大变化,但我怀疑这个“错误”已经让许多用户感到困惑,甚至那些已经意识到它的用户。我知道我一直在忘记。甚至可以让Get-ItemGet-ChildItem 使用相同的ToString(),无论是哪个。

对于激进的(并且可能引发地狱)解决方案,“修复”Get-ChildItem 以仅返回子项(或错误)并使dir 成为根据需要调用Get-ChildItemGet-Item 的函数。然后,这将恢复 Powershell 的“cmdlet 做他们名字所说的事情”的精神,而不是让Get-ChildItem 有时返回子项,有时返回项。 (改变太多了,所以不要屏住呼吸。)

使用 PS 5.1.18362.145 进行测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    相关资源
    最近更新 更多