-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Note:
- This issue is meant to supersede Some cmdlets don't respect
-LiteralPathwhen it comes to backslashes #8158 and Should we do path normalizations on Unix well as on Windows? #6833 and "Rogue" filenames that contain a backslash break automatic globbing for native commands on macOS and Linux #10682 .
From the committee decision at #8587 (comment):
Filesystem accepting both
/and\on all systems is an explicit cross platform experience decision for PowerShell.
Given that it's currently impossible on Unix-like platforms - where \ is a legal filename character - to access or wildcard-match filenames with embedded \ chars., the following fixes are needed:
-
Wildcard matching must able to match
\chars., namely via?or*or[\].- Note that inside
[...],\shouldn't require escaping, analogous to[.]matching a literal.in a regex.
- Note that inside
-
-Pathand-LiteralPatharguments must support`-escaping of\chars. to request their literal treatment. -
The
.PS*provider property values (.PSPath,.PSParentPath,.PSChildName) must reflect the escaped path. -
To-native-path conversions such as with
Convert-Pathmust remove the escaping. -
Native globbing must not break if a wildcard pattern happens to match a filename that contains
\.
Note:
-
Even the above doesn't address the awkwardness of the - unescaped -
.FullNamevalue ofSystem.IO.FileSystemInfonot being directly usable with the filesystem provider; e.g., with the provider bug fixed, something like(Get-ChildItem "$HOME/a\b").FullNamewould return something like/Users/jdoe/a\b- unescaped. -
Similarly, native paths from outside sources with embedded
\- e.g., read from a file - will break in PowerShell commands, unless explicit escaping with-replace '`', '\`'is performed. -
`as the escape char. means that it requires doubling inside"..."and therefore also in unquoted arguments in order to be passed through; i.e., the following calls would be equivalent and match a file literally nameda\b:
Get-Item 'a`\b'
Get-Item "a``\b" # !!
Get-Item a``\b # !! implicitly treated like a "..." string-
Handling
`instances that precede a char. other than\gets quite tricky:-
Literal paths: So as not to break the existing ability to match
`literally in paths,`must be special only before\and before`itself. This follows the model of\use in double-quoted strings in Bash, but introduces the awkwardness of needing to interpret'a`b'and'ab' `` the same (similar to how"a\b"and `"a\b"` are equal in Bash). -
Wildcard paths: Wildcard matching itself always requires doubling of
`for literal use; e.g.,
'a`b' -like 'a`b'is$false, and only'a`b' -like 'a``b'is$true(edge case:'a`' -like 'a`'is also$true- the trailing syntactically incomplete use of`is interpreted as a literal).- However, use of wildcards with the filesystem provider:
- currently makes
Get-Item -Path 'a`b'match a file literally nameda`b, even though it shouldn't. - currently doesn't find a match with
Get-Item -Path 'ab'and neither withGet-Item -Path 'a?', even though it should.
- currently makes
- In other words: wildcard handling by the filesystem provider is currently broken - this may be related to Backtick escaping inconsistent #7999.
- While falling back to literal interpretation is perhaps useful, especially given that
-Pathis the default parameter, this should be fixed, separately.
- However, use of wildcards with the filesystem provider:
-
Steps to reproduce
On macOS or Linux, run the following Pester tests:
# Note: -Skip isn't yet supported at the level of Describe and Context blocks.
# See https://github.com/pester/Pester/issues/442
if ($env:OS -eq 'Windows_NT') {
Write-Warning "Tests apply to Unix-like platforms only" }
else {
Describe "Support for backslashes in Unix filenames" {
BeforeAll {
Push-Location TestDrive:\
# File with literal backslash in its name.
touch 'a\b'
$nativePath = ($PWD.ProviderPath -replace '/$') + '/' + 'a\b'
$escapedName = 'a`\b'
$escapedPath = ((Get-Item .).PSPath -replace '/$') + '/' + $escapedName
# File with literal backtick in its name.
touch 'a`b'
}
It "Backslashes can be matched with wildcards" {
(Get-Item -Path 'a?b').Name | Should -BeExactly 'a\b'
(Get-Item -Path 'a*b').Name | Should -BeExactly 'a\b'
(Get-Item -Path 'a[\]b').Name | Should -BeExactly 'a\b'
}
It "Backtick-escaped backslashes match literal ones in filenames" {
(Get-Item -Path 'a`\b').Name | Should -BeExactly 'a\b'
(Get-Item -LiteralPath 'a`\b').Name | Should -BeExactly 'a\b'
}
It "Backticks not preceding a backslash or backtick are literals in literal paths" {
(Get-Item -LiteralPath 'a`b').Name | Should -BeExactly 'a`b'
}
It "Doubled backticks are also literals in literal paths" {
(Get-Item -LiteralPath 'a``b').Name | Should -BeExactly 'a`b'
}
It "Backtick-escaped backticks must be recognized as a literal backtick in wildcard paths" {
(Get-Item -Path 'a``?').Name | Should -BeExactly 'a`b'
}
It "Provider properties contain escaped paths" {
(Get-Item -LiteralPath 'a`\b').PSChildName | Should -BeExactly $escapedName
(Get-Item -LiteralPath 'a`\b').PSPath | Should -BeExactly $escapedPath
}
It "Convert-Path removes the PS-specific escaping" {
Get-Item -LiteralPath 'a`\b' | Convert-Path | Should -BeExactly $nativePath
}
It "Native globbing doesn't break when a filename with a backslash is among the matches" {
/bin/echo a* | Should -Not -Match '\*'
}
AfterAll {
Pop-Location
}
}
}Expected behavior
All tests should pass.
Actual behavior
All tests except "Backticks not preceding a backslash or backtick are literals in literal paths" fail.
Environment data
PowerShell Core 6.2.0-rc.1