最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

GlobbingWildcard problem with PowerShell `-Path` cmdlets - Stack Overflow

programmeradmin1浏览0评论

I have some files with "meta-characters" in their name, for eg. brackets:

'test[txt].0',  'test[xml].0', 'test[xml].1' | % {New-Item $_} | Out-Null

I can get those files with a glob:

Resolve-Path -Path 'test*'

Path
----
C:\test[txt].0
C:\test[xml].0
C:\test[xml].1

Or a single one of them using backtick-escapes:

Resolve-Path -Path 'test`[xml`].0'

Path
----
C:\test[xml].0

But I can't get the ones that start with test[xml]. using backtick-escapes and a "wildcard":

Resolve-Path -Path 'test`[xml`].*'

What would be the correct -Path to use?

I have some files with "meta-characters" in their name, for eg. brackets:

'test[txt].0',  'test[xml].0', 'test[xml].1' | % {New-Item $_} | Out-Null

I can get those files with a glob:

Resolve-Path -Path 'test*'

Path
----
C:\test[txt].0
C:\test[xml].0
C:\test[xml].1

Or a single one of them using backtick-escapes:

Resolve-Path -Path 'test`[xml`].0'

Path
----
C:\test[xml].0

But I can't get the ones that start with test[xml]. using backtick-escapes and a "wildcard":

Resolve-Path -Path 'test`[xml`].*'

What would be the correct -Path to use?

Share Improve this question edited Mar 7 at 8:58 Fravadona asked Mar 6 at 10:08 FravadonaFravadona 17.3k1 gold badge28 silver badges47 bronze badges 2
  • 2 Try with: 'test``[xml``]*' – Mathias R. Jessen Commented Mar 6 at 11:10
  • 1 I have to say, the provided dupes are mostly about using -LiteralPath or a single backtick to escape the meta characters. -LiteralPath doesn't answer the question, and using a single literal backtick doesn't work here; why the latter doesn't work is a total mystery... – Fravadona Commented Mar 6 at 12:17
Add a comment  | 

3 Answers 3

Reset to default 3

To work around this bug, a possible solution is to avoid using any backtick-escape sequence; just enclose the opening bracket inside brackets:

Resolve-Path -Path test[[]xml].*

Path
----
C:\test[xml].0
C:\test[xml].1

remark: here it doesn't matter if test[[]xml].* is unquoted, single-quoted or double-quoted

To match files that start with test[xml] using a single glob in PowerShell, you need to escape the brackets properly.

Resolve-Path -Path 'test``[xml``].*'

In PowerShell, the backtick (`) is used as the escape character. Since you need to escape the brackets, you should use double backticks to escape each bracket due to a bug. Hopefully, they will fix it in upcoming version.

Preface:

  • In cases where paths are meant to be literal ones that just so happen to contain [ and ] characters, the proper solution is to use the -LiteralPath parameter instead of the (possibly positionally implied) -Path parameter, as discussed in this answer;
    -LiteralPath can be shorted to -lp in PowerShell (Core) 7.

  • In the case at hand, the paths are by design PowerShell wildcard patterns.


You're seeing a long-standing bug that affects all provider cmdlets (including Get-ChildItem, for instance), first reported in 2018 in GitHub issue #7999, under the title "Backtick escaping inconsistent", which captures the gist of the problem:

  • Situationally, for no apparent reason, you must doubly escape [ and ] characters in order for them to be treated literally rather than as wildcard metacharacters, i.e. as verbatim ``[ and ``]

  • Also, sometimes you get away with escaping only [ (not also ]), such as in the case at hand (which is how it should be, given that an ] in isolation is not a metacharacter):

    # Effective for now, but MAY BREAK IN THE FUTURE.
    Resolve-Path './test``[xml].*'
    
  • The specific variation of the bug is that the double escaping unexpectedly becomes necessary due to escaped [ (and possibly ]) being combined with (unescaped) * or ?.

On a general note:

  • Since `, the so-called backtick also serves as the escape character in expandable (interpolating) strings, "..." (as opposed to verbatim strings, '...'), each ` to be passed through to the target command must be doubled again; this also applies to bareword arguments (unquoted command arguments), which are implicitly treated like expandable strings.

  • Therefore, the equivalents of the command above are:

    # Double-quoted argument.
    Resolve-Path "./test````[xml].*"
    
    # Bareword argument
    Resolve-Path ./test````[xml].*
    

Caveat:

  • While the above workaround and its syntactic variations are effective for now, they will break should the bug be fixed in a future PowerShell 7 version.

  • See the next section for future-proof workarounds.


Alternative, future-proof workarounds, where escaping works as expected:

  • As shown in your own answer, the simplest workaround is to make [ part of a character set ([...]), inside of which escaping is not needed; that is, use [[]:

      Resolve-Path ./test[[]xml].*
    
    • As you point out, because `-escaping is then not involved, this has the added advantage of not needing to vary the pattern based on whether '...' vs. "..." quoting / a bareword is used.
  • Use filtering via -like, the wildcard matching operator, in a post-processing step via Where-Object; while less efficient, this works predictably:

      Resolve-Path * | Where-Object Path -like '*[\/]test`[xml].*'
    
      # With Get-ChildItem, more simply:
      Get-ChildItem | Where-Object Name -like 'test`[xml].*'
    
  • In the context of Get-ChildItem, if the wildcard metacharacters are confined to the last path component, you can express that component via a -Filter argument, in which [ and ] do not require escaping:

      # Note that -LiteralPath . can be omitted here.
      Get-ChildItem -LiteralPath . -Filter test[xml].*
    
    • The caveat is that the wildcard "language" of the -Filter parameter generally differs from PowerShell's own wildcards: in addition to -Filter not supporting character sets and ranges (e.g., [abc] or [a-c]) - which is why [ and ] don't require escaping - the matching has legacy quirks for backward compatibility - see this answer for details.
发布评论

评论列表(0)

  1. 暂无评论