Переименуйте файлы последовательно, и если файл уже существует (конфликт имен), просто увеличьте итератор, чтобы дать файлу новое имя

У меня есть этот код для массового переименования всех файлов .mkv и .mp4 в выбранном мной каталоге:

$i = 0; Get-ChildItem "$env:Userprofile\Videos\Movie_Best_Clips" -Filter "vlc-record-2024*.mp4" -Recurse | %{Rename-Item $_.FullName -NewName ($_.Directory.Name+'_'+'_{0:D4}.mp4' -f $i++)};
$i = 0; Get-ChildItem "$env:Userprofile\Videos\Movie_Best_Clips" -Filter "vlc-record-2024*.mkv" -Recurse | %{Rename-Item $_.FullName -NewName ($_.Directory.Name+'_'+'_{0:D4}.mkv' -f $i++)};

Внутри есть несколько каталогов $env:Userprofile\Videos\Movie_Best_Clips, в этих папках находятся файлы, соответствующие шаблону vlc-record-2024*.mp4 или vlc-record-2024*.mkv.

Теперь я хочу, не внося каких-либо серьезных изменений в код, включить проверку того, существует ли файл с тем же именем, что и имя, созданное итератором, или нет в данном каталоге, до или внутри строки Rename-Item.

Если такой файл уже существует, просто выполните поведение continue Like и увеличьте итератор, а затем дайте файлу новое имя, чтобы избежать ошибок переименования элемента.

Так, например, если файл с именем «MOVIENAME 2024 ENGLISH 1080P.mkv__0002.mp4» уже существует (в том же каталоге, что и существующий файл «vlc-record-2024» *, который необходимо переименовать), просто переименуйте соответствующий файл с помощью « MOVIENAME 2024 ENGLISH 1080P.mkv__0003.mp4" и так на каждой итерации.

Я видел этот ответ, но ответчик сделал код слишком длинным, я хочу сделать это как можно короче, но не могу понять, как этого добиться, любая помощь приветствуется.

🤔 А знаете ли вы, что...
PowerShell поддерживает объектно-ориентированное программирование и работу с объектами .NET.


1
50
2

Ответы:

Обновлено: избавился от ошибочного оператора тестового пути и добавил переименование в try-catch для лучшего устранения неполадок.

Get-ChildItem "C:\Users\kakoscdo-admin\Projekte\new2\logs" -Filter "*mkv" -Recurse  | sort CreationTime -Descending| ForEach-Object {
    $noNewNameFound=$true
    while($noNewNameFound){
        $newName= $_.Directory.Name+'_'+'_{0:D4}.mkv' -f $i
        write-host "try renaming $($_.fullname) to $newName"
        if (test-path (Join-Path $_.DirectoryName $newname)){$i++; write-host "$newName allready exists, try next"}
        else{
            write-host "new name not exist yet try renaming"
            write-host "$($_.parent)\$newname"
            try{
                Rename-Item $_.FullName -NewName $newName
                if ($?){write-host "successfully renamed"}
                $noNewNameFound=$false
            }catch{$noNewNameFound=$true; write-host "error renaming $_.error, try next name"}
            $i++
        }
    }
}   

Решено

Вероятно, вы могли бы сделать это за один вызов Get-ChildItem, используя хеш-таблицу, содержащую индекс для каждого расширения. Также нет необходимости в цикле ForEach-Object, если вы используете скриптовый блок с задержкой привязки.

$i = @{ '.mkv' = 0; '.mp4' = 0 }
$getChildItemSplat = @{
    Include = 'vlc-record-2024*.mkv', 'vlc-record-2024*.mp4'
    Recurse = $true
    Path    = "$env:Userprofile\Videos\Movie_Best_Clips"
}

Get-ChildItem @getChildItemSplat | Rename-Item -NewName {
    while ($true) {
        $name = '{0}_{1:D4}{2}' -f $_.Directory.Name, $i[$_.Extension]++, $_.Extension
        if (-not (Test-Path (Join-Path $_.DirectoryName $name))) {
            break
        }
    }

    $name
}