【问题标题】:renaming multiple folders (works with errors!)重命名多个文件夹(有错误!)
【发布时间】:2020-11-14 11:38:28
【问题描述】:

我是 PowerShell 的新手,并且编写了以下脚本,使用 ISE,尝试重命名同一目录中的一堆文件夹,这些文件夹的日期格式严格为 20201130 到 2020-11 -30(只需添加破折号) 脚本有点工作,但我有 3 个问题。

1- 运行时抛出了一堆与Rename-Item 相关的错误 错误:

Rename-Item : Source and destination path must be different.
At line:13 char:25
+ ... ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (D:\Google Drive...Term 2\testings:String 
   ) [Rename-Item], IOException
    + FullyQualifiedErrorId : RenameItemIOError,Microsoft.PowerShell.Commands.Renam 
   eItemCommand

2- 当我使用名为 (234567890) 的文件夹对其进行测试时,它仍然可以工作,尽管此文件夹的长度不等于 8!

3- 当上述重命名发生时,结果名称是“1234-56-7890”,这很奇怪,因为$MyNewName 应该以 2 个字符结尾! $file.Substring( 6 , 2 )

脚本:

$FileNameArr_All = (Get-ChildItem).Name
$i = 0

foreach($file in $FileNameArr_All){
    
    if ( ($file -match "^\d+$") -and ($file.Length -eq 8) ){
    
        [string] $MyNewName = $file.Substring( 0 , 4 )+"-"+$file.Substring( 4 , 2 )+"-"+$file.Substring( 6 , 2 )
        
        #the actual renamining of the item, where the error is:
        Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }

        $message = "the item " + $file + " has been renamed : " + $MyNewName
        Write-Output $message
        $i ++

        Write-Output $file.Length
    }
}
if ($i -eq 0){
    Write-Output "No mathcing items found."
}
else{
    $message2 = "total of items affected: " + $i
    Write-Output $message2
}

我知道这很多,但它是我的第一篇文章,也是我的第一个脚本,我很感激能帮助你解决任何问题。
非常感谢:)

【问题讨论】:

    标签: powershell


    【解决方案1】:

    现有答案中有很好的信息,但让我从概念上归结为更精简的解决方案:

    • 您正在循环遍历所有目录names单独,但您尝试在每次循环迭代中重命名所有项,因为仅使用 Get-ChildItem - 无参数 - 作为 Rename-Item 的输入:

      • Get-ChildItem | Rename-Item ...所有文件和子目录发送到Rename-Item;您实际上是在尝试将它们全部重命名为它们的 现有 名称(请参阅下一个要点),这是 filesquiet no-op >,但会触发您在 目录 中看到的 Source and destination path must be different 错误。
    • $MyNewName完整 新文件名,因此没有理由在原始 目录名上使用-replace:因为$MyNewName 不是现有名称的子字符串,$_.Name -replace $file, $MyNewName 实际上是 no-op - 现有的 $_.Name 被传递。

      • 如果您要重命名单个项,只需在delay-bind script block ({ ... }) 中传递$MyNewName - - 就足够了。

    但是,您可以简化您的解决方案以使用单个管道,包括使用wildcard expression 匹配感兴趣目录的Get-ChildItem 调用,以及Rename-Item 使用延迟绑定脚本块插入 - 字符。通过基于正则表达式的-replace operator

    # Create two sample directories
    $null = New-Item -Force -Type Directory '12345678', '87654321'
    
    Get-ChildItem -Directory -Path ('[0-9]' * 8) |
      Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose
    

    上面执行了所需的重命名,并且由于使用了common -Verbose parameter,打印了以下内容(为了便于阅读而换行):

    VERBOSE: Performing the operation "Rename Directory" on target "Item: ...\12345678 
             Destination: ...\1234-56-78".       
    VERBOSE: Performing the operation "Rename Directory" on target "Item: ...\87654321
             Destination: ...\8765-43-21".
    

    注意:

    • 如果您想预览重命名操作,请使用common -WhatIf parameterRename-Item

    • 如果您需要知道是否有任何文件匹配并因此被重命名,请先在变量中捕获Get-ChildItem 调用:

      $files = Get-ChildItem -Directory -Path ('[0-9]' * 8)
      
      $files | Rename-Item -NewName { $_.Name -replace '(.{4})(.{2})(.{2})', '$1-$2-$3'  } -Verbose
      
      Write-Verbose -Verbose $(if ($files) { "$($files.Count) directories renamed." } else { 'No matching directories found.' })
      

    【讨论】:

      【解决方案2】:

      而不是...

      Get-ChildItem | Rename-Item -NewName { $_.Name -replace $file, $MyNewName }
      

      试试...

      Rename-Item -Name $file -NewName $MyNewName
      

      【讨论】:

        【解决方案3】:

        您可以让 Where-Object 子句中的正则表达式 -match 检查文件夹名称是否正好有 8 位数字并仅重命名:

        $i = 0
        Get-ChildItem -Path 'D:\Test' -Directory | 
            Where-Object { $_.Name -match '^\d{8}$' } | 
            ForEach-Object {
                $newName = $_.Name -replace '(\d{4})(\d{2})(\d{2})', '$1-$2-$3'
                Write-Host "Renaming folder $($_.FullName) to: $newName"
                $_ | Rename-Item -NewName $newName -WhatIf
                $i++
            }
        
        if ($i) {
            Write-Host "Total of items affected: $i"
        }
        else {
            Write-Host "No matching folder names found"
        }
        

        在这里,-WhatIf 开关确保您只能看到会发生什么。实际上还没有重命名。如果您对该输出感到满意,请从 Rename-Item cmdlet 中删除 -WhatIf 开关。

        此外,正则表达式 -replace 通过捕获 3 个不同“反向引用”中的数字并将它们之间的虚线输出,使得创建新名称格式比多次使用 Substring() 容易得多。

        如果您在任何时候都不关心 Write-Host 消息,代码可以缩短为

        Get-ChildItem -Path 'D:\Test' -Directory | 
            Where-Object { $_.Name -match '^\d{8}$' } | 
            Rename-Item -NewName {$_.Name -replace '(\d{4})(\d{2})(\d{2})', '$1-$2-$3'} -WhatIf
        

        【讨论】:

          【解决方案4】:

          这个脚本更可靠一点,因为它使用“Get-ChildItem”的retun对象,而不仅仅是文件/文件夹名称。

          $i = 0
          Get-ChildItem -Directory "C:\UserData\Test" | ForEach-Object {
              if (($_.Name) -match "^\d{8}$") {
                  [System.String]$NewFolderName = ($_.Name).Insert(6, "-").Insert(4, "-")
                  Rename-Item -Path ($_.FullName) -NewName $NewFolderName
                  Write-Output ("the item {0} ({1}) has been renamed : {2}" -f  ($_.Name), (($_.Name).Length), $NewFolderName)
                  $i++
              }
          }
          
          if ($i) {
              Write-Output ("total of items affected: {0}" -f $i)
          } else{
              Write-Output "No matching items found."
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-07-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-10-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多