Note: This solution is only of interest if you need to trim at most 2 trailing \
chars., want to support /
path separators too, want to handle root paths correctly or are generally interested in regex techniques.
If it's acceptable to trim any nonempty run of trailing \
chars., i.e., also 3 or more (which is quite likely in this case) and root paths need no special treatment, use Martin Brandl's simple solution.
A solution based on PowerShell's -replace
operator with a regular expression that handles both trailing \
and \\
and also works with /
, given that PowerShell accepts both \
and /
as the path separator (which will also make the solution work with PowerShell Core, the cross-platfom edition):[1]
# Remove at most 2 trailing "\" chars.
PS> 'C:\Ravi\' -replace '[\\/]?[\\/]$'
C:\Ravi
#'# More simply, remove any number of trailing "\" chars.
PS> 'C:\Ravi\' -replace '[\\/]+$' #'# equivalent of 'C:\Ravi\'.TrimEnd('\/')
C:\Ravi
[\\/]
is a character class ([...]
) that matches a single character that is either \
(escaped as \\
to be treated as a literal) or /
.
[\\/]?[\\/]
matches one or two \
instances at the end ($
) of the string, [\\/]+
more loosely matches one or more (+
).
Not specifying a replacement string effectively removes the match from the string; if there is no match, the input string is left as-is.
To demonstrate that the approach works with a variety of paths, including UNC paths:
'C:\Ravi', 'C:\Ravi\', 'C:/Ravi/', 'C:\Ravi\\', '\\foo\bar\', 'C:\', '\' | % {
$_ -replace '[\\/]?[\\/]$'
}
The above yields:
C:\Ravi
C:\Ravi
C:/Ravi
C:\Ravi
\\foo\bar
C:
Note, however, that handling of root paths is problematic: C:\
was transformed to C:
, and \
resulted in the empty string.
Fixing that - by leaving a trailing \
in these special cases - requires a significantly more complex regex (slightly simplified by matching any number of trailing path separators):
'C:\Ravi', 'C:\Ravi\', 'C:\', 'C:\\', '\', '\\' | % {
$_ -replace '(?:^((?:[a-z]:)?\\)\\*$)|(.*?)(?:\\+)$', '$1$2'
}
This yields:
C:\Ravi
C:\Ravi
C:\
C:\
\
\
Note how the root paths now end in (one) \
.
The special-casing of root paths is cumbersome, which is why it is sometimes preferable to ensure rather than remove a trailing \
or /
(e.g., C:\Ravi
-> C:\Ravi\
), so as to facilitate building paths with simple string concatenation (without having to worry about doubling \
chars.); the regex becomes simple again:
'C:\Ravi', 'C:\Ravi\', 'C:\', 'C:\\', '\', '\\' | % {
($_ -replace '[\\/]+$') + '\'
}
This yields:
C:\Ravi\
C:\Ravi\
C:\
C:\
\
\
Note how all paths now end in (one) \
.
[1] Sometimes string manipulation is necessary, but oftentimes you can rely on the Join-Path
cmdlet to build paths for you, which handles a trailing \
in the directory part gracefully (e.g., Join-Path C:\Ravi\ file.txt
yields C:\Ravi\file.txt
); by contrast, a trailing \\
is preserved: Join-Path C:\Ravi\\ file.txt
yields C:\Ravi\\file.txt
; however, while that isn't pretty, it is generally benign (such paths still work for accessing the filesystem).