以特定方式重命名文件的脚本 [英] Script for renaming files in a specific way

查看:37
本文介绍了以特定方式重命名文件的脚本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能构建一个脚本(例如 PowerShell),根据特定文本使用特定文本重命名文件?

我有数千个文件,例如:

  • 12345_id_user.pdf

  • 23456_id_user.pdf

  • 34567_id_user.pdf

  • 45678_id_user.pdf

我需要用另一个特定的 id 更改第一部分(数字):

12345 → 98765

23456 → 87654

34567 → 76543

我有需要替换的新 ID 和旧 ID 的列表(excel/记事本/word).

那么,是否可以创建一个脚本来查找名称12345"并将其与新列表进行比较并更改为98765"?

更新 2:

$Path = "C:\Users\oledv\Desktop\TestEnv\";$Text = $arrExcelValuesA#$PathArray = @()#$Results = "C:\temp\test.txt";函数释放引用($ref){([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)[System.GC]::Collect()[System.GC]::WaitForPendingFinalizers()}$arrExcelValuesA = @()$objExcel = 新对象 -ComObject Excel.Application$objWorkbook = $objExcel.Workbooks.Open(C:\Users\oledv\Desktop\TestEnv\TestIds.xlsx")$objWorksheet = $objWorkbook.Worksheets.Item(1)Get-ChildItem $Path -Filter "*.pdf";|ForEach-Object {$FileName = Get-Content $_.Name写输出 $FileName$i = 1做 {$arrExcelValuesA = $objWorksheet.Cells.Item($i, 1).Value()$i++} while ($FileName -eq $arrExcelValuesA)$row = $objWorkSheet.Cells.Find($arrExcelValuesA).row$col = $objWorkSheet.Cells.Find($arrExcelValuesA).column$NewName = $objWorksheet.Cells.Item($row, $col+1).Value()+$arrExcelValuesA.Substring(5)Rename-Item -Path $_.Name -NewName $NewName}

它重命名了第一个文件,但看起来它没有遍历文件夹中的所有文件...

<前>重命名项目:当该文件已存在时无法创建该文件.在 C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 字符:18+ Rename-Item -Path $_.Name -NewName $NewName+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : WriteError: (C:\Users\oledv\...456_id_user.pdf:String) [Rename-Item], IOException+ FullQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand重命名项目:当该文件已存在时无法创建该文件.在 C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 字符:18+ Rename-Item -Path $_.Name -NewName $NewName+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : WriteError: (C:\Users\oledv\...567_id_user.pdf:String) [Rename-Item], IOException+ FullQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand重命名项目:当该文件已存在时无法创建该文件.在 C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 字符:18+ Rename-Item -Path $_.Name -NewName $NewName+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : WriteError: (C:\Users\oledv\...678_id_user.pdf:String) [Rename-Item], IOException+ FullQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand重命名项目:当该文件已存在时无法创建该文件.在 C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 字符:18+ Rename-Item -Path $_.Name -NewName $NewName+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : WriteError: (C:\Users\oledv\...789_id_user.pdf:String) [Rename-Item], IOException+ FullQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand重命名项目:当该文件已存在时无法创建该文件.在 C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 字符:18+ Rename-Item -Path $_.Name -NewName $NewName+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+ CategoryInfo : WriteError: (C:\Users\oledv\Desktop\TestEnv\xxxx.pdf:String) [Rename-Item], IOException+ FullQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

解决方案

正如所评论的,如果您将旧的和新的 ID 值放在这样的 CSV 文件中会简单得多:

"旧ID","新ID"12345"、98765"23456"、87654"34567"、76543"

然后,如下所示:

# 读取此 CSV 以获取 PSObject 数组$ids = Import-CSV -Path 'D:\ReplaceId.csv'# 从 $ids 变量构建一个查找表$hash = @{}$ids |ForEach-Object { $hash[$_.OldID] = $_.NewID }# 接下来,获取名称以 any 开头的所有文件的列表# 列 'OldID' 中的 5 位数字并循环遍历Get-ChildItem -Path '你的目录的路径' -Filter '*.pdf' -File |Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } |ForEach-Object {# 从查找哈希表中获取新 ID 的值# 并将其与文件名的其余部分合并$newName = '{0}{1}' -f $hash[$($_.Name.Substring(0,5))], $_.Name.Substring(5)$_ |Rename-Item -NewName $newName -WhatIf}

如果控制台信息显示正确的替换名称,请删除 -WhatIf 开关以实际开始重命名文件

如果您将 -Recurse 开关添加到 Get-ChildItem cmdlet,代码还将重命名任何子文件夹中的文件.

<小时>更新

<小时>

当然,以上假设在文件夹中没有混合新旧 ID 编号.由于您评论说是这种情况,您将收到 file already exists 错误.为了克服这个问题,您需要确保新文件名在文件夹中是唯一的.例如,您可以这样做.

如果具有该名称的文件已经存在,它会在名称的方括号之间附加一个索引号.

Get-ChildItem -Path 'D:\Test' -Filter '*.pdf' -File |Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } |ForEach-Object {# 从查找哈希表中获取新 ID 的值# 并将其与文件名的其余部分合并$newId = $hash[$($_.Name.Substring(0,5))]$newName = '{0}{1}' -f $newId, $_.Name.Substring(5)# 因为带有新 ID 的文件名可能已经存在,# 你需要通过附加一个索引号来创建一个唯一的文件名$fullName = Join-Path -Path $_.DirectoryName -ChildPath $newName$指数 = 1while (Test-Path -Path $fullName -PathType Leaf) {$newName = '{0}{1}({2}){3}' -f $newId, $_.BaseName.Substring(5), $index++, $_.Extension$fullName = Join-Path -Path $_.DirectoryName -ChildPath $newName}$_ |Rename-Item -NewName $newName -WhatIf}

之前:

<块引用>

D:\TEST12345_id_user.pdf12345_id_user2.pdf12345_id_user3.pdf23456_id_user.pdf34567_id_user.pdf34567_id_user2.pdf76543_id_user2.pdf98765_id_user.pdf

之后:

<块引用>

D:\TEST76543_id_user.pdf76543_id_user2(1).pdf76543_id_user2.pdf87654_id_user.pdf98765_id_user(1).pdf98765_id_user.pdf98765_id_user2.pdf98765_id_user3.pdf

或者如果你想增加你似乎已经应用的索引号,使用这个:

Get-ChildItem -Path 'D:\Test' -Filter '*.pdf' -File |Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } |ForEach-Object {# 从查找哈希表中获取新 ID 的值# 并将其与文件名的其余部分合并$newId = $hash[$($_.Name.Substring(0,5))]$newName = '{0}{1}' -f $newId, $_.Name.Substring(5)# 因为带有新 ID 的文件名可能已经存在,# 你需要通过增加索引号来创建一个唯一的文件名# 获取新名称的基本名称,末尾没有任何索引号$baseName = [System.IO.Path]::GetFileNameWithoutExtension($newName) -replace '\d+$'$extension = $_.Extension# 获取文件夹中已存在的具有相似名称的项目的所有文件和文件夹名称的数组$similar = @(Get-ChildItem $_.DirectoryName -Filter "$baseName*$extension" | Select-Object -ExpandProperty Name)$指数 = 1while ($similar -contains $newName) {$newName = '{0}{1}{2}' -f $baseName, $index++, $extension}$_ |Rename-Item -NewName $newName -WhatIf}

之前:

<块引用>

D:\TEST12345_id_user.pdf12345_id_user2.pdf12345_id_user3.pdf23456_id_user.pdf34567_id_user.pdf34567_id_user2.pdf76543_id_user2.pdf98765_id_user.pdf

之后:

<块引用>

D:\TEST76543_id_user.pdf76543_id_user1.pdf76543_id_user2.pdf87654_id_user.pdf98765_id_user.pdf98765_id_user1.pdf98765_id_user2.pdf98765_id_user3.pdf

Is there a possibility to build a script (PowerShell for instance) where the file will be renamed with specific text according to specific text?

I have thousands of files like:

  • 12345_id_user.pdf

  • 23456_id_user.pdf

  • 34567_id_user.pdf

  • 45678_id_user.pdf

    etc.

And I need to change first part (digits) with another specific id:

12345 → 98765

23456 → 87654

34567 → 76543

I have list (excel/notepad/word) of new ids and old ids that need to be replaced.

So, is it possible to create a script where it will look for name '12345' compare it to new list and change to '98765'?

Update 2:

$Path = "C:\Users\oledv\Desktop\TestEnv\"
$Text = $arrExcelValuesA
#$PathArray = @()
#$Results = "C:\temp\test.txt"

function Release-Ref ($ref) {
    ([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
    [System.GC]::Collect()
    [System.GC]::WaitForPendingFinalizers()
}
$arrExcelValuesA = @()

$objExcel = New-Object -ComObject Excel.Application
$objWorkbook = $objExcel.Workbooks.Open("C:\Users\oledv\Desktop\TestEnv\TestIds.xlsx")
$objWorksheet = $objWorkbook.Worksheets.Item(1)

Get-ChildItem $Path -Filter "*.pdf" | ForEach-Object {
    $FileName = Get-Content $_.Name
    Write-Output $FileName
    $i = 1

    do {
        $arrExcelValuesA = $objWorksheet.Cells.Item($i, 1).Value()
        $i++
    } while ($FileName -eq $arrExcelValuesA)

    $row = $objWorkSheet.Cells.Find($arrExcelValuesA).row
    $col = $objWorkSheet.Cells.Find($arrExcelValuesA).column
    $NewName = $objWorksheet.Cells.Item($row, $col+1).Value()+$arrExcelValuesA.Substring(5)
    Rename-Item -Path $_.Name -NewName $NewName
}

It renames first file, but looks like it doesn't go through all files in folder...

Rename-Item : Cannot create a file when that file already exists.
At C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 char:18
+                  Rename-Item -Path $_.Name -NewName $NewName
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\Users\oledv\...456_id_user.pdf:String) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

Rename-Item : Cannot create a file when that file already exists.
At C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 char:18
+                  Rename-Item -Path $_.Name -NewName $NewName
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\Users\oledv\...567_id_user.pdf:String) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

Rename-Item : Cannot create a file when that file already exists.
At C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 char:18
+                  Rename-Item -Path $_.Name -NewName $NewName
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\Users\oledv\...678_id_user.pdf:String) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

Rename-Item : Cannot create a file when that file already exists.
At C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 char:18
+                  Rename-Item -Path $_.Name -NewName $NewName
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\Users\oledv\...789_id_user.pdf:String) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

Rename-Item : Cannot create a file when that file already exists.
At C:\Users\oledv\Desktop\TestEnv\Check.ps1:40 char:18
+                  Rename-Item -Path $_.Name -NewName $NewName
+                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\Users\oledv\Desktop\TestEnv\xxxx.pdf:String) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand

解决方案

As commented, it would be a lot simpler if you put the old and new ID values in a CSV file like this:

"OldID","NewID"
"12345","98765"
"23456","87654"
"34567","76543"

Then, something like below should work:

# read this CSV to get an array of PSObjects
$ids = Import-CSV -Path 'D:\ReplaceId.csv'

# build a lookup table from the $ids variable
$hash = @{}
$ids | ForEach-Object { $hash[$_.OldID] = $_.NewID }

# next, get a list of all files that have names starting with any 
# of the 5 digits from column 'OldID' and loop through
Get-ChildItem -Path 'THE PATH TO YOUR DIRECTORY' -Filter '*.pdf' -File | 
    Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } | 
    ForEach-Object {
        # get the value for the new ID from the lookup hashtable
        # and combine it with the remainder of the filename
        $newName = '{0}{1}' -f $hash[$($_.Name.Substring(0,5))], $_.Name.Substring(5)
        $_ | Rename-Item -NewName $newName -WhatIf
    }

If the console info shows the correct replacement names, remove the -WhatIf switch to actually start renaming the files

If you add the -Recurse switch to the Get-ChildItem cmdlet, the code will also rename files inside any subfolder.


Update


Of course, the above assumes there is no mix of Old and New Id numbers in the folder. Since you commented that this is the case you will get file already exists errors. To overcome that, you need to make sure the new filenames are unique inside the folder. You can do that for instance like this.

It appends an index number between brackets to the name if a file with that name already exists.

Get-ChildItem -Path 'D:\Test' -Filter '*.pdf' -File | 
    Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } | 
    ForEach-Object {
        # get the value for the new ID from the lookup hashtable
        # and combine it with the remainder of the filename
        $newId = $hash[$($_.Name.Substring(0,5))]
        $newName = '{0}{1}' -f $newId, $_.Name.Substring(5)
        # since a filename with the new ID may already exist, 
        # you need to create a unique filename by appending an indexnumber
        $fullName = Join-Path -Path $_.DirectoryName -ChildPath $newName
        $index = 1
        while (Test-Path -Path $fullName -PathType Leaf) {
            $newName = '{0}{1}({2}){3}' -f $newId, $_.BaseName.Substring(5), $index++, $_.Extension
            $fullName = Join-Path -Path $_.DirectoryName -ChildPath $newName
        }
        $_ | Rename-Item -NewName $newName -WhatIf
    }

Before:

D:\TEST
    12345_id_user.pdf
    12345_id_user2.pdf
    12345_id_user3.pdf
    23456_id_user.pdf
    34567_id_user.pdf
    34567_id_user2.pdf
    76543_id_user2.pdf
    98765_id_user.pdf

After:

D:\TEST
    76543_id_user.pdf
    76543_id_user2(1).pdf
    76543_id_user2.pdf
    87654_id_user.pdf
    98765_id_user(1).pdf
    98765_id_user.pdf
    98765_id_user2.pdf
    98765_id_user3.pdf

Or if you want to increase the index number you already seem to apply, use this:

Get-ChildItem -Path 'D:\Test' -Filter '*.pdf' -File | 
    Where-Object { $hash.Keys -contains $_.Name.Substring(0,5) } | 
    ForEach-Object {
        # get the value for the new ID from the lookup hashtable
        # and combine it with the remainder of the filename
        $newId    = $hash[$($_.Name.Substring(0,5))]
        $newName  = '{0}{1}' -f $newId, $_.Name.Substring(5)
        # since a filename with the new ID may already exist, 
        # you need to create a unique filename by incrementing the indexnumber

        # get the basename of the new name without any index numbers at the end
        $baseName  = [System.IO.Path]::GetFileNameWithoutExtension($newName) -replace '\d+$'
        $extension = $_.Extension
        # get an array of all file and folder names of items with a similar name already present in the folder
        $similar = @(Get-ChildItem $_.DirectoryName -Filter "$baseName*$extension" | Select-Object -ExpandProperty Name)
        $index = 1
        while ($similar -contains $newName) {
            $newName = '{0}{1}{2}' -f $baseName, $index++, $extension
        }

        $_ | Rename-Item -NewName $newName -WhatIf
    }

Before:

D:\TEST
    12345_id_user.pdf
    12345_id_user2.pdf
    12345_id_user3.pdf
    23456_id_user.pdf
    34567_id_user.pdf
    34567_id_user2.pdf
    76543_id_user2.pdf
    98765_id_user.pdf

After:

D:\TEST
    76543_id_user.pdf
    76543_id_user1.pdf
    76543_id_user2.pdf
    87654_id_user.pdf
    98765_id_user.pdf
    98765_id_user1.pdf
    98765_id_user2.pdf
    98765_id_user3.pdf

这篇关于以特定方式重命名文件的脚本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆