使用 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 递归重命名文件的主要内容,如果未能解决你的问题,请参考以下文章