简体   繁体   中英

Globbing patterns in windows command prompt/ powershell

I would like to know if there is any way to achieve this behavior on windows, for example:

/b?n/ca? /etc/pa??wd -> executes 'cat /etc/passwd'

In PowerShell you can use Resolve-Path which Resolves the wildcard characters in a path, and displays the path contents.

Example: I want to locate signtool.exe from the Windows SDK which typically resides in "c:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe" where there could be any other version(s) installed.

So I could use: Resolve-Path 'c:\program*\Windows Kits\10\bin\*\x64\signtool.exe'

EDIT:

If you want to execute it directly you can use the & invocation operator eg

&(Resolve-Path 'c:\wind?ws\n?tepad.exe')

  • With limited exceptions in PowerShell, on Windows there is no support for shell-level globbing - target commands must perform their own resolution of wildcard patterns to matching filenames; if they don't, globbing must be performed manually and the results passed as literal paths; see the bottom section for background information.

  • PowerShell :

    • Perhaps surprisingly, you can invoke an executable by wildcard pattern, as zett42 points out, though that behavior is problematic (see bottom section):

       # Surprisingly DOES find C:\Windows\System32\attrib.exe # and invokes it. C:\Windows\System3?\attr*.exe /?
      • Generally, you can discover commands, including external programs, via the Get-Command cmdlet.
    • Many file-processing cmdlets in PowerShell do perform their own globbing (eg, Get-ChildItem , Remove-Item ); if you're calling commands that do not, notably external programs that don't, you must perform globbing manually , up front , except on Unix -like platforms when calling _external programs, where PowerShell does perform automatic globbbing (see bottom section):

      • Use Convert-Path to get the full, file-system-native paths of matching files or directories.

        • While Resolve-Path may work too, it returns objects whose .ProviderPath property you need to access to get the same information ( stringifying these objects, as happens implicitly when you pass them to external programs, yields their .Path property, which may be based on PowerShell-only drives that external programs and .NET APIs know nothing about.)
      • For more control over what is matched, use Get-ChildItem and access the result objects' .Name or .FullName property, as needed; for instance, Get-ChildItem allows you to limit matching to files ( -File ) or directories ( -Directory ) only.

      • PowerShell makes it easy to use the results of manually performed globbing programmatically ; the following example passes the full paths of all *.txt files in the current directory to the cmd.exe 's echo command as individual arguments; PowerShell automatically encloses paths with spaces in "..." , if needed:

         cmd /c echo (Get-ChildItem -Filter *.txt).FullName
      • Generally, note that PowerShell's wildcard patterns are more powerful than those of the host platform's file-system APIs, and notably include support for character sets (eg [ab] ) and ranges (eg [0-9] ); another important difference is that ? matches exactly one character, whereas the native file-system APIs on Windows match none or one .

        • However, when using the -Filter parameter of file-processing cmdlets such as Get-ChildItem , the host platform's patterns are used, which - while limiting features - improves performance; a caveat is that on Unix-like platforms ? then seemingly acts like on Windows, ie causing it to match none or one character.
  • cmd.exe (Command Prompt, the legacy shell) :

    • cmd.exe does not support calling executables by wildcard pattern; some of cmd.exe 's internal commands (eg, dir and del ) and some standard external programs (eg, attrib.exe ) do perform their own globbing; otherwise you must perform globbing manually , up front :

      • where.exe , the external program for discovering external programs fundamentally only supports wildcard patterns in executable names (eg where find*.exe ), not in paths , which limits wildcard-based lookups to executables located in directories listed in the PATH environment variable.

         :: OK - "*" is part of a *name* only where.exe find*.exe :: !! FAILS: "*" or "?" must not be part of a *path* :: !! -> "ERROR: Invalid pattern is specified in "path:pattern"." where.exe C:\Windows\System32\find*.exe
      • Globbing via dir appears to be limited to wildcard characters in the last path component:

         :: OK - "*" is only in the *last* path component. dir C:\Windows\System32\attri* :: !! FAILS: "*" or "?" must not occur in *non-terminal* components. :: !! -> "The filename, directory name, or volume label syntax is incorrect." dir C:\Windows\System3?\attri*
      • Using manual globbing results programmatically is quite cumbersome in cmd.exe and requires use of for statements (whose wildcard matching has the same limitations as the dir command); for example, using the syntax for batch files ( .cmd or .bat files):

        • To use the resolved executable file path for invocation (assuming only one file matches):

           @echo off setlocal :: Use a `for` loop over a wildcard pattern to enumerate :: the matching filenames - assumed to be just *one* in this case, :: namely attrib.exe, and save it in a variable. for %%f in (C:\Windows\System32\attr*.exe) do set "Exe=%%f" :: Execute the resolved filename to show its command-line help. "%Exe%" /?
        • To pass matching filenames as multiple arguments to a single command:

           @echo off setlocal enableDelayedExpansion :: Use a `for` loop over a wildcard pattern to enumerate :: matching filenames and collect them in a single variable. set files= for %%f in (*.txt) do set files=!files! "%%f" :: Pass all matching filenames to `echo` in this example. echo %files%

Background information:

  • On Unix -like platforms, POSIX-compatible shells such as Bash themselves perform globbing (resolving filename wildcard patterns to matching filenames), before the target command sees the resulting filenames , as part of a feature set called shell expansions (link is to the Bash manual).

  • On Windows , cmd.exe (the legacy shell also known as Command Prompt) does NOT perform such expansions and PowerShell mostly does NOT .

    • That is, it is generally up to each target command to interpret wildcard patterns as such and resolve them to matching filenames.

      • That said, in PowerShell, many built-in commands, known as cmdlets , do support PowerShell's wildcard patterns , notably via the -Path parameter of provider cmdlets, such as Get-ChildItem .

      • Additionally and more generally, cmdlet parameters that represent names often support wildcards too; eg, Get-Process exp* lists all processes whose image name start with exp , such as explorer .

      • Note that the absence of Unix-style shell expansions on Windows also implies that no semantic distinction is made between unquoted and quoted arguments (eg, *.txt vs. "*.txt" ): a target command generally sees both as verbatim *.txt .

    • In PowerShell , automatic globbing DOES occur in these limited cases :

      • Perhaps surprisingly, an executable file path can be invoked via a wildcard pattern :

        • as-is, if the pattern isn't enclosed in '...' or "..." and/or contains no variable references or expressions; eg:

           C:\Windows\System3?\attri?.exe
        • via & , the call operator , otherwise; eg:

           & $env:SystemRoot\System32\attri?.exe
        • However, this feature is of questionable utility - When would you not want to know up front what specific executable you're invoking? - and it is unclear whether it was implemented by design , given that inappropriate wildcard processing surfaces in other contexts too - see GitHub issue #4726 .

          • Additionally, up to at least PowerShell 7.2.4, if two or more executables match the wildcard pattern, a misleading error occurs, suggesting that no matching executable was found - see GitHub issue #17468 ; a variation of the problem also affects passing a wildcard-based path (as opposed to a mere name ) that matches multiple executables to Get-Command .

          • In POSIX-compatible shells, the multi-match scenario is handled differently, but is equally useless: the first matching executable is invoked, and all others are passed as its arguments .

      • On Unix -like platforms only, PowerShell emulates the globbing feature of POSIX-compatible shells when calling external programs , in an effort to behave more like the platform-native shells; if PowerShell didn't do that, something as simple as ls *.txt would fail, given that the external /bin/ls utility would then receive verbatim *.txt as its argument.

        • However, this emulation has limitations , as of PowerShell 7.2.4:
          • The inability to use wildcard patterns that contain spaces - see GitHub issue #10683 .
          • The inability to include hidden files - see GitHub issue #4683 .
          • A still experimental feature , available in preview versions of 7.3, PSNativePSPathResolution , automatically translates wildcard patterns based on PowerShell- only drives to their underlying native file-system paths; however, this feature is currently overzealous - see GitHub issue #13640 - and inherently bears the risk of false positives - see GitHub issue #13644

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM