使用 Powershell 递归重命名文件

Posted

技术标签:

【中文标题】使用 Powershell 递归重命名文件【英文标题】:Recursively renaming files with Powershell 【发布时间】:2014-03-03 21:48:38 【问题描述】:

我目前有一行可以批量重命名我当前所在文件夹中的文件。

dir | foreach  move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") 

此代码适用于我当前所在的任何目录,但我想要的是从包含 11 个子文件夹的父文件夹运行脚本。我可以通过单独导航到每个文件夹来完成我的任务,但我宁愿运行一次脚本并完成它。

我尝试了以下方法:

get-childitem -recurse | foreach  move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") 

任何人都可以在这里指出正确的方向吗?我对 Powershell 一点也不熟悉,但在这种情况下它很适合我的需求。

【问题讨论】:

Recursively renaming files in Powershell的可能重复 感谢您将我指向该线程。但是,即使阅读了另一个问题的答案,我仍然遇到困难。我要么得到文件不存在,要么文件正被另一个进程使用。 【参考方案1】:

你很亲密:

Get-ChildItem -File -Recurse | %  Rename-Item -Path $_.PSPath -NewName $_.Name.replace(".mkv.mp4",".mp4")

【讨论】:

感谢您的回答,但我现在收到以下信息:Move-Item : The process cannot access the file because it is being used by another process. At line:1 char:45 + get-childitem -recurse | foreach move-item <<<< -literal $_.FullName $_.FullName.replace(".mkv.mp4",".mp4") + CategoryInfo : WriteError: (D:\The Wire\Season 1:DirectoryInfo) [Move-Item], IOException + FullyQualifiedErrorId : MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand @Matthew,我相信这是因为你使用 move-item 而不是 rename-item,修复了我的帖子 这样就解决了问题。我正在使用 move-item,因为所有文件名中都有方括号,并且 rename-item 之前对我不起作用。感谢您的帮助。 Cannot rename because item at 'Settings.png' does not exist。它在根目录中工作,但在子文件夹中失败。 @TheMuffinMan 更新为更具体的路径。【参考方案2】:

有一个不为人知的功能就是专门为这种情况而设计的。简而言之,您可以执行以下操作:

Get-ChildItem -Recurse -Include *.ps1 | Rename-Item -NewName  $_.Name.replace(".ps1",".ps1.bak") 

这通过为参数 NewName 传递一个脚本块来避免使用 ForEach-Object。 PowerShell 足够聪明,可以评估每个通过管道传输的对象的脚本块,设置 $_ 就像使用 ForEach-Object 一样。

【讨论】:

我在 powershell 2.0 中测试了这个,它只适用于 1 个文件夹,并且不会递归到子文件夹中...... 我刚刚更新了 sn-p 以使用 V2 - 它需要 - 包括。 V3 更智能一点,不需要 -Include。 甜蜜,+1 无需 foreach 即可 花了很多时间阅读有关 foreach 等不适用于子文件夹的帖子。这是唯一有效的方法。 得益于多年的事后诸葛亮:此功能现在有了一个名称并记录在案:delay-bind script blocks【参考方案3】:

请注意,如果您仍然遇到Cannot rename because item at '...' does not exist. 之类的错误问题,您可能正在使用一些超长路径和/或带有方括号等“特殊解释”字符的路径(即[])。

对于此类情况,使用 -LiteralPath/-PSPath 以及特殊前缀 \\?\(对于 UNC 路径,您需要使用前缀 \\?\UNC\)用于最多 32k 个字符的路径。我还建议尽早过滤(使用Get-ChildItem)以提高性能(更少Rename-Item 调用更好)。


$path = 'C:\Users\Richard\Downloads\[Long Path] THE PATH TO HAPPINESS (NOT CLICKBAIT)\...etc., etc.'
# -s is an alias for -Recurse
# -File for files only
# gci, dir, and ls are all aliases for Get-ChildItem
#   Note that among the 3, only `gci` is ReadOnly.
gci -s -PSPath $path -File -Filter "*.mkv.mp4" |
    # ren, rni are both aliases for Rename-Item
    #   Note that among the 2, only `rni` is ReadOnly.
    # -wi is for -WhatIf (a dry run basically). Remove this to actually do stuff.
    # I used -replace for regex (for excluding those super rare cases)
  rni -wi -PSPath  "\\?\$($_.FullName)"  -NewName  $_.Name -replace '\.mkv(?=\.mp4$)','' 

【讨论】:

很高兴知道;请注意,在 PowerShell [Core] v6+ 中,现在默认启用了长路径支持,并且使用\\?\ 前缀不仅没有必要,而且可能会导致问题。跨度> 另请注意,您的命令使用来自gci -PSPath (-LiteralPath) 参数的both 管道输入,这将不会不行。

以上是关于使用 Powershell 递归重命名文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Powershell 中将文件重命名为小写

如何在 PowerShell 中使用条件语句重命名文件

使用 PowerShell 重命名 FTP 上的文件

使用 PowerShell 重命名 zip 以匹配其内容

如果文件存在,Powershell 移动项目重命名

在 PowerShell 中使用加号重命名文件