0

I tried following Remove leading spaces in Windows file names but it's not working for my use case.

I have a lot of folders and filenames that either have a blank space at the front or at the end. How would I go about removing those spaces in bulk?

This was the command-line command I used after following the linked post:

for /R %A IN ("* ") do @for /F "tokens=*" %B IN ("%~nxA") do @ren "%A" "%B"

But it didn't work out.

Update: thank you to all who replied trying to help. I think there is just a Windows-level glitch in the file system. I ended up just having to manually create new folders without leading and trailing spaces and then dragging all the files over manually then renaming those to non-trailing and leading names as well.

Aedam
  • 141
  • 1
  • 9
  • 2
    Are you looking for a powershell solution or batch ? it's unclear – Santiago Squarzon Apr 23 '22 at 15:59
  • 1
    @SantiagoSquarzon I'm OK with a PowerShell or batch solution. I just need well over 100 folders and file names changed, whatever is the most efficient way of going about that. – Aedam Apr 23 '22 at 17:00
  • The trailing white spaces on specifically files are between the file name and it's extension (ie: `file .ext`) or after the extension (ie: `file.ext `) ? – Santiago Squarzon Apr 23 '22 at 17:03
  • @SantiagoSquarzon it's mainly folder names, so " test" and "test " but for file names it's " test.jpg" and "test .jpg" – Aedam Apr 23 '22 at 17:13

3 Answers3

1

It's unclear whether or not you want a PowerShell solution, but there's a reasonable assumption to be made you might.

If you wanted a PowerShell solution, you could try this:

function Test-LeadingTrailingWhitespace {
    param(
        [Parameter(Mandatory)]
        [String]$String
    )

    $String[0] -eq ' ' -Or $String[-1] -eq ' '
}

Get-ChildItem -Path "<path_to_folder>" | ForEach-Object { 
  if ($_.PSIsContainer -And (Test-LeadingTrailingWhitespace -String $_.Name)) {
    $Destination = Split-Path -Path $_.FullName -Parent
    $NewName = $_.Name.Trim()
    Move-Item -Path $_ -Destination (Join-Path -Path $Destination -ChildPath $NewName)
  }
  elseif (Test-LeadingTrailingWhitespace -String $_.BaseName) {
    $Destination = Split-Path -Path $_.FullName -Parent
    $NewName = $_.BaseName.Trim() + $_.Extension
    Move-Item -Path $_ -Destination (Join-Path -Path $Destination -ChildPath $NewName)
  }
}

To be on the safe side, you could add -WhatIf or -Confirm on the Move-Item cmdlet. The former will tell you what would have changed without that parameter without actually making any changes (like a 'dry run'). The latter will prompt you for confirmation before making each change, giving you a chance to validate incrementally and not make changes en masse from the moment you hit enter.

Trim() is a method available for all strings in PowerShell:

Returns a new string in which all leading and trailing occurrences of a set of specified characters from the current string are removed.

codaamok
  • 717
  • 3
  • 11
  • 21
  • Thank you for that, when I ran it, every item in the folder said "Rename-Item : Source and destination path must be different." – Aedam Apr 23 '22 at 16:58
  • @Aedam Interesting... sounds like that's a known issue when trying to rename folders... https://github.com/PowerShell/PowerShell/issues/14903 - it seems you can ignore this error as it's just complaining the name hasn't changed. – codaamok Apr 23 '22 at 17:03
  • @codaamok How do I go about ignoring that error? – Aedam Apr 23 '22 at 17:04
  • @Aedam, have a look here https://stackoverflow.com/a/66359942/11954025 – Daniel Apr 23 '22 at 17:04
  • @Daniel I followed the "If directories are (also) targeted, as in your case, you need to explicitly filter out input items for which no actual renaming would occur:" section but It still won't work. None of the folders/files I'm changing have any similiarties. I'm still getting the error on every file/folder it's checking – Aedam Apr 23 '22 at 17:10
  • @codaamok the issue is that no file/folder is being changed, so that error appears 100% for all items in the main directory – Aedam Apr 23 '22 at 17:11
  • @Aedam I added some more code to check if the file or folder name actually contains trailing or leading whitespace, and only execute the `Rename-Item` if that's true, so that should help avoid the issue. – codaamok Apr 23 '22 at 17:20
  • @codaamok that didn't work either. i have no idea what's causing this. I restarted my computer just in case it was a file lock issue and the same error. – Aedam Apr 23 '22 at 17:39
  • If you a have a folder named " folder1 " and a folder named "folder1" in the same directory, you will get that error because " folder1 " cannot be renamed to "folder1" because the other exists. Could that be what is happening for you? – Daniel Apr 23 '22 at 17:50
  • @Aedam to workaround the issue, I changed cmdlet from `Rename-Item` to `Move-Item`. – codaamok Apr 23 '22 at 18:01
0

You can loop over files and folder and check if they actually have a leading or trailing whitespace before renaming, this would avoid errors like:

Rename-Item: Source and destination path must be different.

We can use the -match matching operator with a simple regex ^\s|\s$ (starts with whitespace or ends with whitespace - regex101 link for a simple example) to see if the file or folder should be renamed:

Get-ChildItem path\to\startingfolder -Recurse | ForEach-Object {
    $newName = switch($_) {
        # handle folders
        { $_.PSIsContainer -and $_.Name -match '^\s|\s$' } {
            $_.Name.Trim()
            break
        }
        # handle files
        { $_.BaseName -match '^\s|\s$' -or $_.Extension -match '^\s|\s$' } {
            $_.BaseName.Trim() + $_.Extension.Trim()
            break
        }
        # if none of the above conditions were true, continue with next item
        Default {
            return
        }
    }
    Rename-Item -LiteralPath $_.FullName -NewName $newName
}
Santiago Squarzon
  • 41,465
  • 5
  • 14
  • 37
  • This is the error I am getting with this "Get-ChildItem : Could not find a part of the path" – Aedam Apr 23 '22 at 17:42
  • @Aedam `path\to\startingfolder` should be changed for your started folder :) – Santiago Squarzon Apr 23 '22 at 17:43
  • it was changed to the correct path – Aedam Apr 23 '22 at 17:44
  • @Aedam I have updated the code and tested it, let me know if it does work for you. I didn't see errors. – Santiago Squarzon Apr 23 '22 at 17:51
  • 1
    @SantiagoSquarzon I really like the cleanliness of your answer compared to mine! Did you know `switch` statement can also process a collection, too? e.g. `switch (Get-ChildItem path\to\startingfolder -Recurse) { ...` could have worked, but if you were to do that I would avoid the use of `return` in the default case. – codaamok Apr 23 '22 at 18:10
  • 1
    @codaamok thank you, yes I know, the problem with using `switch` to enumerate is that it would collect all elements before enumerating them this would bring a new problem, if a folder is renamed, then `Rename-Item` would throw errors for any file inside the renamed folder since it's absolute path changed (due to the renaming of it's parent folder). In this case the best option is pipeline processing I think – Santiago Squarzon Apr 23 '22 at 18:26
0

Personally, I'd do this in two steps to rename folders and files separately. This to overcome the problem that when a folder is renamed, the items inside that folder all have a new path.

  • Using switch -Force allows renaming items such as hidden or read-only files
  • Using -ErrorAction SilentlyContinue swallows the error when the new name is equal to the existing name
$rootPath = 'X:\thepath'
# first the folders and subfolders (deepest nesting first)
(Get-ChildItem -Path $rootPath -Directory -Recurse | Sort-Object FullName -Descending) | 
    Rename-Item -NewName {$_.Name.Trim()} -Force -ErrorAction SilentlyContinue

# next the files
(Get-ChildItem -Path $rootPath -File -Recurse) | 
    Rename-Item -NewName {'{0}{1}' -f $_.BaseName.Trim(), $_.Extension.Trim()} -Force -ErrorAction SilentlyContinue
Theo
  • 57,719
  • 8
  • 24
  • 41