最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How do I preserve the order of one array to the second in PowerShell? - Stack Overflow

programmeradmin1浏览0评论

I am trying to rewrite a entire directory of files. I am renaming each file under certain conditions. Then I capitalize each word in a string that represents the filename. But after entering the loop to capitalize each word, the array becomes unordered according to the first array it was given.

# contains the list of filenames.
$files = Get-ChildItem $dirPath -File | ForEach-Object {$_.Name}

# Begin the loop and manipulation
foreach ($item in $files) {
   $myString = $item -replace "-", " "
   $myString = $myString -replace "_", " "
   $myString = $myString -replace "Whatsnew", "whats new"
   $myString = $myString -replace "howto", "how to"
   $words = $myString.Split(" ")
   $capitalizedWords = $words | ForEach-Object {
      $_.Substring(0,1).ToUpper() + $_.Substring(1).ToLower()
   }
   $result = $capitalizedWords -join " "
   $new_path = ($dirPath + "\" + $result)
   Rename-Item "$($dirPath)\$item" "$new_path"
}

This renames the files but the file I capitalized to Installing.pdf is only 200kb and the original file that is ordered in the $files array is 700kb. I do not understand how to keep both arrays indexed in the same order.

I am trying to rewrite a entire directory of files. I am renaming each file under certain conditions. Then I capitalize each word in a string that represents the filename. But after entering the loop to capitalize each word, the array becomes unordered according to the first array it was given.

# contains the list of filenames.
$files = Get-ChildItem $dirPath -File | ForEach-Object {$_.Name}

# Begin the loop and manipulation
foreach ($item in $files) {
   $myString = $item -replace "-", " "
   $myString = $myString -replace "_", " "
   $myString = $myString -replace "Whatsnew", "whats new"
   $myString = $myString -replace "howto", "how to"
   $words = $myString.Split(" ")
   $capitalizedWords = $words | ForEach-Object {
      $_.Substring(0,1).ToUpper() + $_.Substring(1).ToLower()
   }
   $result = $capitalizedWords -join " "
   $new_path = ($dirPath + "\" + $result)
   Rename-Item "$($dirPath)\$item" "$new_path"
}

This renames the files but the file I capitalized to Installing.pdf is only 200kb and the original file that is ordered in the $files array is 700kb. I do not understand how to keep both arrays indexed in the same order.

Share Improve this question asked Feb 7 at 7:33 Johnny VanJohnny Van 111 silver badge2 bronze badges New contributor Johnny Van is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct. 2
  • 2 Add the -WhatIf switch to rename-item and make sure the replacement is as expected. You might have multiple files with almost same names, so the renamed Installed.pdf isn't what you think it is. – vonPryz Commented Feb 7 at 7:52
  • Have you got an example set of the original filenames that this happens with? – mclayton Commented Feb 7 at 11:56
Add a comment  | 

2 Answers 2

Reset to default 1

I do agree with @vonPryz that the most likely scenario is name collision.
Try this: it also has a few things that might help your script to be a bit easier to follow.

# No reason to remove properties, we can use them later.   
$FileList = Get-ChildItem -File -Path $Path

foreach ($File in $FileList) {

    # If the list of replacement gets any larger, I suggest making a hashtable to
    # loop through instead.   
    $NameReplaced = $File.BaseName -replace '-', ' ' -replace '_', ' ' -replace 'Whatsnew', 'whats new' -replace 'howto', 'how to' 
        
    # If accented characters give problems, replace InvartiantCulture with
    # CurrentCulture, CurrentUICulture or a specific Culture as necessary.   
    $NewName = [cultureinfo]::InvariantCulture.TextInfo.ToTitleCase($NameReplaced) + $file.Extension
    
    # remove -WhatIf once you are sure everything is right
    Rename-Item -LiteralPath $File.FullName -NewName $NewName -WhatIf
}

Here are 3 example filenames. It is the list of the Python Documentation Zip file. I am just learning thanks for the WhatIf suggestion, I will use that from now on. As for the code given to me from SirTao, that script did not uppercase the filenames that had single words such as tutorial.pdf stayed tutorial.pdf

  • howto-annotations.pdf
  • whatsnew.pdf
  • tutorial.pdf

I had an entire conversation with Gemini AI for about 5 hours last night. Gemini gave me strong suggestions. I suggested executing one script and then executing a separate second one, and Gemini agreed. I tried executing the first script that kept the list in order but did not capitalize the single-word filenames, as I executed the second script; PowerShell gave me an error about the file already existing. I then gave Gemini the two variations of the script I originally provided here. Gemini updated its script to handle the error and created a solution for an absolute path.

The error here is something I saw when I was younger but I forgot because I stopped studying computers. In order to manipulate files. You have to construct the full filename from scratch. I learned you cannot let a language like C handle filenames even if it has a library for file I/O. I forget why manipulating filenames causes this behavior but the issue is about the language's privileges and how the directory path is an actual place in memory.

Here is the code Gemini finished with. It is definitely similar to my original script compared to the other recommendations given by Gemini, but more error handling and the solution for the perfect file path. I say this comment because if you use Gemini, you should still provide your solutions to the project.

# Get files, preserve order
$files = Get-ChildItem $dirPath -File | Sort-Object FullName

foreach ($item in $files) {
   $filename = $item.Name # Get the original filename (including extension)
   $extension = $item.Extension # Store the extension separately
   $myString = $filename -replace "-", " "
   $myString = $myString -replace "_", " "
   $myString = $myString -replace "(?i)Whatsnew", "whats new"
   $myString = $myString -replace "(?i)howto", "how to"
   $words = $myString.Split(" ")
   $result = ""
   foreach ($word in $words) {
     if ($word.Length -gt 0) {
       $result += $word.Substring(0, 1).ToUpper() + $word.Substring(1).ToLower() + " "
     }
   }
   $result = $result.Trim() + $extension # Add the extension back
   $new_path = Join-Path -Path $dirPath -ChildPath $result

   # Check if the new file already exists
   if (Test-Path $new_path) {
       # Add a number to the filename to make it unique (only if needed)
       $counter = 1
       do {
           $unique_path = Join-Path -Path $dirPath -ChildPath ("{0} ({1}){2}" -f $result.Replace($extension,""), $counter, $extension) # Add counter and preserve extension
           $counter++
       } until (-not (Test-Path $unique_path))
       $new_path = $unique_path
   }
   Rename-Item $item.FullName $new_path -WhatIf # Use -WhatIf first!
}

As for PowerShell not doing as it says it can. Common misbehavior of computers.

发布评论

评论列表(0)

  1. 暂无评论