Powershell command to trim path if it ends with “\

2019-04-20 21:21发布

I need to trim path if it ends with \.

C:\Ravi\

I need to change to

C:\Ravi

I have a case where path will not end with \ (Then it must skip).

I tried with .EndsWith("\"), but it fails when I have \\ instead of \.

Can this be done in PowerShell without resorting to conditionals?

4条回答
Lonely孤独者°
2楼-- · 2019-04-20 21:43

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).

查看更多
虎瘦雄心在
3楼-- · 2019-04-20 21:46

Consider using TrimEnd instead (especially if you are working with UNC Path):

"C:\Ravi\".TrimEnd('\')
查看更多
老娘就宠你
4楼-- · 2019-04-20 21:50

no need to overcomplicate

"C:\Ravi\".trim('\')
查看更多
We Are One
5楼-- · 2019-04-20 22:08

You mention needing to differentiate between paths ending in "\" and "\\" and possibly handling those differently. While you can use .Trim("\") or .TrimEnd("\") to remove the trailing "\" character in the example you gave, both those methods will strip all trailing slashes from your path.

The following regex will return True if your path ends in a single "\" but false if it ends in multiple "\" characters:

$Path -match '.+[^\\]\\$'

The regex means:

  1. A string of as many characters as possible,
  2. Up to something that is NOT a backslash
  3. Followed by one backslash

Giving:

"C:\Ravi\" -match '.+[^\\]\\$'
True

"C:\Ravi\\" -match '.+[^\\]\\$'
False

Hope this helps / is interesting. :-)

查看更多
登录 后发表回答