【问题标题】:Script for renaming files in a specific way以特定方式重命名文件的脚本
【发布时间】:2020-01-27 12:51:39
【问题描述】:

是否有可能构建一个脚本(例如 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/notepad/word)。

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

更新 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
}

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

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

【问题讨论】:

  • 你有明确的要求,也有策略去做。还请展示一些你已经尝试过的代码
  • 您还需要确定您的列表格式,在这三种格式中,我建议使用纯文本格式,即记事本。然后您需要edit your question 来包含该文件的内容和布局示例。没有它,我们只能猜测。
  • @Theo 当然,我已经停在那里了......
  • @Compo 我决定试试excel
  • 如果您从该 Excel 创建一个 CSV 文件并让它有两列,第一列是要查找的值,第二列是要替换它们的值(您的代码似乎只从 Excel 文件中读取一列)。有了这个,您可以简单地使用 -Filter 参数获取与要查找的值匹配的目录中的文件,并使用第二列中的值重命名它们。

标签: powershell text replace


【解决方案1】:

正如评论的那样,如果您将旧 ID 值和新 ID 值放在 CSV 文件中,如下所示:

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

然后,类似下面的东西应该可以工作:

# 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
    }

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

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


更新

当然,以上假设文件夹中没有混合旧 ID 号和新 ID 号。由于您评论过这种情况,您将收到 file 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
    }

之前:

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

之后:

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

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

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
    }

之前:

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

之后:

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

【讨论】:

  • 非常感谢您的评论。我也会尝试这个选项。但是,我设法使用此代码重命名了第一个文件,但看起来它并没有遍历文件夹中的所有文件。我将添加为 UPD2
  • 问题是文件可以用相同的 id 重复多次,如 12345_id_user.pdf / 12345_id_user2.pdf / 12345_id_user3.pdf 和 12345 仍然需要用 98765 更改
  • @Oleg_D 您显然在文件夹中混合了旧的和新的 ID 编号文件,问题中并不清楚。我已将新代码添加到 uniqify 新文件名。
  • 是的!你说得对,.cvs 方式非常方便和清晰......现在我明白了:) 非常感谢你的帮助和时间!
  • @Oleg_D 在这种情况下,我认为使用$newId = ($_.Name -split '_')[0] 或使用像$newId = ([regex] '^([^_]+)').Matches($_.Name).Groups[1].Value$newId = ([regex] '^(\d+)(?=_)').Matches($_.Name).Groups[1].Value 这样的正则表达式会更容易
猜你喜欢
  • 2021-02-05
  • 1970-01-01
  • 2019-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多