web-dev-qa-db-fra.com

Renommer récursivement des fichiers avec Powershell

J'ai actuellement une ligne pour renommer par lots des fichiers dans un dossier dans lequel je suis actuellement.

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

Ce code fonctionne parfaitement pour n'importe quel répertoire dans lequel je suis actuellement, mais ce que je veux, c'est exécuter un script à partir d'un dossier parent qui contient 11 dossiers enfants. Je peux accomplir ma tâche en accédant à chaque dossier individuellement, mais je préfère exécuter le script une fois et en finir avec lui.

J'ai essayé ce qui suit:

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

Quelqu'un peut-il m'indiquer ici la bonne direction? Je ne connais pas du tout Powershell, mais cela correspondait à mes besoins dans ce cas.

21
Matthew

Vous étiez proche:

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

Il existe une fonctionnalité peu connue qui a été conçue exactement pour ce scénario. En bref, vous pouvez faire quelque chose comme:

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

Cela évite d'utiliser ForEach-Object en passant un bloc de script pour le paramètre NewName. PowerShell est suffisamment intelligent pour évaluer le bloc de script pour chaque objet qui est canalisé, en définissant $ _ comme il le ferait avec ForEach-Object.

32
Jason Shirk

Notez que si vous rencontrez toujours un problème avec des erreurs comme Cannot rename because item at '...' does not exist., vous travaillez peut-être avec des chemins très longs et/ou des chemins avec des caractères "spécialement interprétés" comme des crochets (c'est-à-dire []).

Pour de tels scénarios, utilisez -LiteralPath/-PSPath avec le préfixe spécial \\?\ (pour les chemins UNC, vous voudrez utiliser le préfixe \\?\UNC\) pour les chemins jusqu'à 32k caractères. Je suggère également de filtrer tôt (avec Get-ChildItem) pour de meilleures performances (moins Rename-Item les appels sont meilleurs).


$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$)','' }
0
YenForYang