'Removing trailing and ending blank spaces in folder and file names on Windows in bulk

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.



Solution 1:[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.

Solution 2:[2]

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
}

Solution 3:[3]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3