【问题标题】:Using Get-ChildItem -Exclude or -Include returns nothing使用 Get-ChildItem -Exclude 或 -Include 不返回任何内容
【发布时间】:2016-11-11 04:09:34
【问题描述】:

我的 C: 目录中有一个包含许多文件的列表。如果我尝试在其上运行 -Exclude,我不会得到任何回报。与 -Include 相同。如果我使用过滤器,它会返回我期望得到的东西。我不明白它应该做什么吗?

这是我正在运行但一无所获的示例:

Get-ChildItem -Path C: -Exclude "*.txt"

我一无所获。如果我跑

Get-Childitem -filter "*.txt"

我拿回来了:

  Mode                LastWriteTime         Length Name                                                                               
----                -------------         ------ ----                                                                               
-a----        11/7/2007   8:00 AM          17734 eula.1028.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.1031.txt                                                                      
-a----        11/7/2007   8:00 AM          10134 eula.1033.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.1036.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.1040.txt                                                                      
-a----        11/7/2007   8:00 AM            118 eula.1041.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.1042.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.2052.txt                                                                      
-a----        11/7/2007   8:00 AM          17734 eula.3082.txt                                                                      
               7/7/2016   8:50 AM             93 HaxLogs.txt                                                                        
-a----         7/8/2016   8:30 AM              0 Test.txt 

【问题讨论】:

  • 对我来说它没有问题,但是您是否尝试过不使用引号作为扩展名?喜欢Get-ChildItem -Path C: -Exclude *.txt

标签: powershell powershell-4.0


【解决方案1】:

总结和补充gravity'sBrian Reynolds's 有用的答案:

您的方法存在两个明显的问题:

  • 定位 C: 可能不会(总是)做你想做的,因为 C: 指的是驱动器 C 上的当前位置(工作目录) : 目前。

    • 要定位驱动器 C: 的 根文件夹,您必须使用 C:\,我假设这就是您在本答案其余部分中的意思。
  • 使用 -Exclude(以及 -Include)参数,既没有 -Recurse 也没有以 \* 结尾的 -Path 值通常不会产生任何结果。 意外?确实 - 请参阅下文了解更多信息。

    • 因此,Get-Item -Path C:\* -Exclude *.txt - 注意从Get-ChildItemGet-Item 的切换以及C:\ 之后的* - 需要让您的命令对位于直接中的项目起作用仅限C:\

背景资料:

使用 provider-native -Filter 参数通常优于 -Include,因为:

  • 它比-Include 快得多,因为提供者自己在源执行过滤,而不是让PowerShell在所有对象之后稍后应用过滤器已收到。

  • 它不需要您切换到Get-Item 并将\* 附加到-Path 参数值。

    • 例如,Get-ChildItem -Path C:\ -Filter *.txt 可以很好地匹配 C: 根目录中的所有 *.txt 文件。

也就是说,有警告

  • -Filter 支持的通配符模式语言的功能比 PowerShell 少 - 值得注意的是,它不支持 [0-9] 等字符集/范围 - 可能会意外匹配短 (8.3) 文件名,并且还有其他遗留的怪癖 - 请参阅 this well-researched answer 了解血腥细节。

  • -Filter 仅支持单个 模式,而-Include 支持多个(数组 模式)。

很遗憾,-Filter 始终是一个(包含)过滤器,因此不能用于提供-Exclude 的功能。


-Include / -ExcludeGet-ChildItem 的实现不直观且存在缺陷:

旁注:如果您只使用 one -Include 模式(而不是 -Exclude),将模式直接附加到-Path 论点;例如:Get-ChildItem C:\*.txt

tl;dr

如果您也使用-Recurse(如果您使用-Recurse 这个解决方法是不需要):

# IMPORTANT: Workaround isn't needed if you're using -Recurse.
#   * "\*" was appended to the input path
#   * Get-*ChildItem* was switched to Get-*Item*
Get-Item C:\path\to\* -Include ...
Get-Item C:\path\to\* -Exclude ...

PowerShell (Core) v7+ 中,如果您的输入路径是 文字 的,您也可以使用 Get-ChildItem-LiteralPath而不是(可能在位置上暗示)-Path(当前目录使用.。):

# IMPORTANT: Works in PowerShell (Core) only.
#            Note the use of -LiteralPath.
Get-ChildItem -LiteralPath C:\path\to -Include ...
Get-ChildItem -Literalpath C:\path\to -Exclude ...

  • Windows PowerShell 中有一个彻底的错误,当使用 -LiteralPath 时,-Include / -Exclude悄悄地忽略了。从(至少)v7.0 开始,这已在 PowerShell (Core) 中得到修复(可以公平地假设它不会在 Windows PowerShell 中得到修复,这将以后只收到关键修复)。

  • -Include-Exclude 并不像人们直观预期的那样工作,这是GitHub issue #3304 的主题:

    • -Include-Exclude 修改-Path 参数的leaf(最后一个)路径组件,即文件或目录names系统路径。

    • 这意味着模式首先应用到指定文件夹路径本身的叶子组件应用到子项,如果有的话。

    • 如果输入路径不以\*结尾且未指定-Recurse,则含义如下:

      • -Include:如果输入路径的最后一个路径组件-Include模式匹配,则排除输入路径本身(不包括) ,并且从不查看路径的 child 项 - 没有任何输出。

      • -Exclude:类似地,如果输入路径的最后一个路径组件确实-Exclude模式匹配,则输入路径本身被排除在外,并且path 的 child 项永远不会被查看 - 没有任何输出。

        • 目录为目标 - 例如,Get-ChildItem -Path C:\ -Exclude Windows) 似乎从 v7.0 开始完全被破坏:它要么根本不产生任何输出, 或在类 Unix 平台上失败,无论使用何种模式,-Include-Exclude 都失败 - 请参阅 GitHub issue #11649
      • 如前所述,如果使用-Recurse,问题不会出现,因为即使输入路径本身是强制进入输入路径的子树,不包括/排除。

  • 除非需要-Recurse,否则获得预期行为的唯一方法是将
    Get-ChildItem C:\path\to -Include / -Exclude替换为
    Get-Item C:\path\to\* -Include / -Exclude - 请注意使用 Get-Item 而不是 Get-ChildItem,并且 \* 被附加到 -Path 参数中。

    • 相比之下,如果您将Get-ChildItem *-Exclude 结合使用,并且非排除项中有目录Get-ChildItem 会意外输出其内容时间>;这不会发生在-Include 上,并且通常不会发生在子目录匹配通配符表达式-Path 参数和/或-Filter 参数)中。
  • 从 PowerShell 7.2 开始的问题总结

    • GitHub issue #3304(如上所述):违反直觉地将 -Include / -Exclude 模式应用于输入本身而不是其子级。

    • GitHub issue #11649: Get-ChildItem -Path <rootPath> -Exclude <anyPattern> 意外产生 no 输出(即使 不应排除任何内容,因为排除模式通常应用于输入路径,例如如/c:\)。

    • GitHub issue #9126: -Include / -Exclude 在使用 -Recurse 时意外跟随符号链接。

    • GitHub issue #8662:性能问题:-Include / -Exclude 比使用Where-Object 的事后过滤要慢(!)。

    • 一个相关的功能请求GitHub issue #15159,它建议引入排除子文件夹子树的能力(而不是仅仅排除与模式本身匹配的项目,但不排除他们的孩子),带有一个新参数,例如-ExcludeSubtree


示例:-Include / -Exclude 的问题使用

注意:要使下面的所有命令都能按照直觉预期工作,请将 Get-ChildItem C:\Windows 替换为 Get-Item C:\Windows\* - 注意使用不同的 cmdlet,Get-Item 和附加的 \*

# HAPPENS TO WORK, BUT IS NOT ROBUST:
# Matches all w* items *inside* C:\Windows, but
# ONLY because w* happens to match 'Windows' - the last input
# path component - too.
Get-ChildItem C:\Windows -Include w*

# HAPPENS TO WORK, BUT IS NOT ROBUST:
# Matches all items whose names *don't* start with a-v *inside* C:\Windows, but
# ONLY because [a-v]* happens not to exclude 'Windows' - the last input
# path component - too.
Get-ChildItem C:\Windows -Exclude [a-v]*


# OUTPUTS NOTHING:
# Because t* doesn't match 'Windows', the child items of 
# 'C:\Windows' are not considered.
Get-ChildItem C:\Windows -Include t*

# OUTPUTS NOTHING:
# Because w* matches 'Windows', it is excluded, and
# the child items of 'C:\Windows' are not considered.     
Get-ChildItem C:\Windows -Exclude w*

【讨论】:

  • 天哪,这是对所有不同挂断的彻底整合!真正深入推理的方式! :) 您是否在某个地方发现了这个,还是您自己研究过的?
  • 这令人难以置信。从字面上看,-Include/-Exclude 只是被默默地忽略;因此它们是不可靠的。使用 -Exclude 选项编写脚本来删除子目录是非常危险的,因为它可能会删除它们。这是一个巨大的问题,因为 Remove-Item 文档说它的 -Recurse 参数也“已知不起作用”,并建议使用 Get-ChildItem 将其传递给命令作为解决方法。但是Get-ChildItem也明显坏了!真是一团糟。
  • P.S.,@Triynko:GitHub issue #5699 中讨论了一个类似的潜在破坏性问题。
  • 小修正,@Triynko: -Include / -Exclude 没有被忽略 - 它们只是没有以人们期望的方式应用:它们被不恰当地应用于输入路径(第一个)而不是(仅)到他们的子项,由此产生的看似不可预测的行为可能比仅仅忽略更糟糕。至于Remove-Item 帮助主题中的警告-Recurse / 结合-Recurse-Include:让我们尝试澄清/更新/删除这些警告:请参阅Github docs issue #8134
  • @AgentRev,是的,这是违反直觉的,但这不是 PowerShell 的错:-Filter 参数通常是特定于提供程序的,这对于文件系统路径意味着它是处理通配符匹配,它有很多遗留的怪癖,比如你提到的那个 - 见this answer
【解决方案2】:
Get-ChildItem -Path "C:\*" -Include "*.txt"

这个关于-Include 应该如何工作的示例将为您提供您所期望的结果。请注意,我还在路径参数中提供了一个通配符,以将路径明确定义为“根 C: 中的任何文件”,而不是“C:”本身。

来源: https://technet.microsoft.com/library/hh849800.aspx

此链接中的示例 3,以防它失效(请注意此处路径中的通配符):

C:\> Get-ChildItem –Path "C:\Windows\Logs\*" -Include "*.txt" -Exclude "A*"

【讨论】:

  • 谢谢。由于某种原因,路径中的通配符确实有效。
  • 这就是让我发疯的事情:当 API/命令根据输入以不同的方式运行时。当然,这应该发生,但我的具体意思是在这种情况下。当您单独通过路径时,它假定通配符*。当您添加 -Include-Exclude 时,它会停止做出这种假设,并且文档不会这么说。更重要的是,命令是 CALLED Get-ChildItem。它应该得到儿童物品。在所有情况下都不需要通配符。
  • 哇。显然,在路径中添加通配符使一切正常。这太令人困惑了
【解决方案3】:

使用后面不带斜杠的“C:”是您没有得到想要的结果的原因。这被解释为当前目录的相对路径,而不是 C 驱动器的根目录。 (见:Path with no slash after drive letter and colon - what does it point to?

如果您改用“C:\”,它应该可以按预期工作。

编辑:我的错误;我专门针对仅使用“-exclude”的示例做出回应。

【讨论】:

  • 其实不然。自己试试。 Get-ChildItem -Path "C:\" -Include "*.txt" 不产生任何结果,而 Get-ChildItem -Path "C:\*" -Include "*.txt" 向我显示所有带有 .txt 的文件扩展名
  • 是的,除非我添加 *.在 C:\.我不知道为什么,因为我在位置 C: 并且如果我使用 Get-ChildItem C: 或 Get-ChildItem C:\ 我会取回所有文件。似乎只有 -Include 和 -Exclude 为我执行此操作。我正在运行 PSVersion - 5.0.10586.122
  • (不幸的是)确实,在没有 -Recurse 的情况下附加 * 需要使用 -Include / -Exclude),但这个答案对C:C:\ 有很好的关系。 /跨度>
【解决方案4】:

这似乎是一个错误(因为父属性的字符串版本是空字符串?)。使用子目录,它可以正常工作:

get-childitem c:\windows -directory -exclude *.dll

你可以用不同的方式指定根目录,得到一个奇怪的错误信息:

get-childitem Microsoft.PowerShell.Core\FileSystem::C:\ -exclude *.txt

get-childitem : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
At line:1 char:1
+ get-childitem Microsoft.PowerShell.Core\FileSystem::C:\ -exclude wind ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], PSArgumentException
    + FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.GetChildItemCommand

或者,在 osx 中:

get-childitem / -directory -exclude *.txt

get-childitem : Cannot process argument because the value of argument "path" is not valid. Change the value of the "path" argument and run the operation again.
At line:1 char:1
+ get-childitem / -directory -exclude var
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (:) [Get-ChildItem], PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.GetChildItemCommand

这是 powershell 6 及更高版本的解决方法:

get-item c:\ | get-childitem -exclude *.txt

【讨论】:

    猜你喜欢
    • 2020-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-15
    • 1970-01-01
    • 2017-08-28
    • 1970-01-01
    相关资源
    最近更新 更多