问题
I currently have a line to batch rename files in a folder that I am currently in.
dir | foreach { move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") }
This code works perfectly for whatever directory I'm currently in, but what I want is to run a script from a parent folder which contains 11 child-folders. I can accomplish my task by navigating to each folder individually, but I'd rather run the script once and be done with it.
I tried the following:
get-childitem -recurse | foreach { move-item -literal $_ $_.name.replace(".mkv.mp4",".mp4") }
Can anyone please point me in the right direction here? I'm not very familiar with Powershell at all, but it suited my needs in this instance.
回答1:
You were close:
Get-ChildItem -File -Recurse | % { Rename-Item -Path $_.PSPath -NewName $_.Name.replace(".mkv.mp4",".mp4")}
回答2:
There is a not well-known feature that was designed for exactly this scenario. Briefly, you can do something like:
Get-ChildItem -Recurse -Include *.ps1 | Rename-Item -NewName { $_.Name.replace(".ps1",".ps1.bak") }
This avoids using ForEach-Object by passing a scriptblock for the parameter NewName. PowerShell is smart enough to evaluate the scriptblock for each object that gets piped, setting $_ just like it would with ForEach-Object.
回答3:
Note that if you are still having issue with errors like Cannot rename because item at '...' does not exist.
, you may be working with some super long paths and/or paths with 'specially-interpreted' characters like square brackets (i.e. [
]
).
For such scenarios, use -LiteralPath
/-PSPath
along with the special prefix \\?\
(for UNC paths you will want to use the prefix \\?\UNC\
) for paths up to 32k characters. I also suggest filtering early (with Get-ChildItem
) for improved performance (less Rename-Item
calls are better).
$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$)','' }
来源:https://stackoverflow.com/questions/21611551/recursively-renaming-files-with-powershell