【问题标题】:How can one delete files in a folder matching a regular expression using PowerShell?如何使用 PowerShell 删除与正则表达式匹配的文件夹中的文件?
【发布时间】:2014-07-09 04:03:22
【问题描述】:

我知道我的 Windows 计算机上许多不需要的文件的文件名的共同特征。如何使用单个 regular expression PowerShell 命令从给定文件夹或文件夹层次结构中删除所有这些文件?

【问题讨论】:

    标签: regex windows file powershell file-io


    【解决方案1】:

    我会用这个:

    (Get-ChildItem -Path $Path | Select -ExpandProperty Fullname) -match <regex> | Remove-Item
    (Get-ChildItem -Path $Path -Recurse | Select -ExpandProperty Fullname) -match <regex> | Remove-Item
    

    或者如果您拥有 V3 或更高版本,因此您有自动成员枚举:

     (Get-ChildItem -Path $Path).Fullname -match <regex> | Remove-Item
     (Get-ChildItem -Path $Path -Recurse).Fullname -match <regex> | Remove-Item
    

    仅当您当前的工作目录是您要从中删除文件的目录并且所有文件都在该目录中时,名称才会起作用(递归可能会找到多个具有相同名称但路径不同的文件)。

    【讨论】:

    • 将整个 FileInfo 对象(而不是字符串)传递给 Remove-Item 命令将删除它,即使它不在您当前的路径中。与名称匹配可避免简单的正则表达式模式意外匹配父文件夹的误报匹配。
    • 没错,但这似乎是保护自己免受自己正则表达式影响的拐杖。
    • 如果您希望匹配文件/文件夹名称中的模式,那么确实不需要完整路径。 OP 说正则表达式匹配文件名中的模式,引用整个路径意味着您必须在正则表达式模式上花费更多时间并使其更准确。我不会将引用 Name 称为拐杖,而是仅处理所需任务所需的内容。
    【解决方案2】:

    您可以将 Get-ChildItem 命令通过接受 RegEx 模式的 Where-Object 过滤器进行管道传输,然后将其管道传输到 Remove-Item。我认为这会让你获得比使用 Select-String 更快、更好的结果。使用如下命令:

    Get-ChildItem $Path | Where{$_.Name -Match "<RegEx Pattern>"} | Remove-Item
    

    Name 属性只会匹配文件或文件夹的名称以及文件的扩展名。它不会与路径上的其他事物匹配。这将通过管道传递一个 FileInfo 对象,Remove-Item 将其作为管道输入并删除有问题的文件。

    如果您想包含路径的子文件夹,您可以在 Get-ChildItem 命令中添加 -Recurse 开关,它看起来像这样:

    Get-ChildItem $Path -Recurse | Where{$_.Name -Match "<RegEx Pattern>"} | Remove-Item
    

    如果您只想删除文件,您可以在 Where 语句中指定,方法是查看 FileInfo 对象的 PSIContainer 属性并通过在对象前面加上感叹号来反转它:

    Get-ChildItem $Path -Recurse | Where{$_.Name -Match "<RegEx Pattern>" -and !$_.PSIsContainer} | Remove-Item
    

    【讨论】:

    【解决方案3】:

    你可以使用命令,

    ls -name | select-string -pattern ".*\(\d+\).*" | %{rm $_}
    

    引号的内容是你的正则表达式。此示例中的正则表达式搜索文件名中包含 (#) 的文件,其中 # 是任何非负整数。这对于删除同一组文件被多次转储的文件夹中的重复项非常有用,例如由音乐管理器转储。

    如果你在 -name 之后添加 -r

    ls -name -r | select-string -pattern ".*\(\d+\).*" | %{rm $_}
    

    它将遍历子文件夹并删除所有子文件夹中的匹配文件。

    命令结构如下:

    • ls 是 powershell 命令 get-childitem 的别名。它列出了当前文件夹中的所有元素。 -name 参数指定只生成名称;我不想要文件大小等其他信息。
    • select-string 基本上等同于 UNIX grep,它将模式(正则表达式)匹配到一堆行分隔的字符串。 -pattern 参数将 cmdlet 设置为采用正则表达式。
    • %{rm $} 是一个 foreach 循环。这就是说,“对于通过管道传输到我的每一行(在这种情况下来自 select-string)”,请执行以下操作,其中 $ 是给定的行。在这种情况下,我们正在对项目进行 rm-ing,其中 rm 是 Remove-Item 的别名。

    【讨论】:

    • Select-String 用于在文件中查找信息。它返回 MatchInfo 对象,其中包含找到匹配项的文件名和行号等信息。在这种情况下,所有这些信息都是无用的,它增加的开销也被浪费了。一个简单的 -match 操作会更快、更简单并且同样有效。
    • 我要补充一点,-name 参数仅输出字符串,因此您会丢失所有其他文件元数据(LengthLastWriteTime 等)。我建议改为匹配 Name 属性(如 mjolinor 建议的那样使用 -match)。
    • @Bill_Stewart - 我建议使用全名,尤其是在您进行递归时。
    • @mjolinor - 是的,如果名称的路径部分很重要,我当然同意。