Globbing patterns in windows command prompt/ powershell
Asked Answered
S

2

3

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'

Spaulding answered 30/5, 2022 at 12:59 Comment(3)
The path globbing behavior is possible, (but the exact command is not since there's no /bin/cat executable in Windows). Simply use the & invocation operator and Get-Command (alias gcm): & (gcm 'Get-C?nte?t') .\spycloud.pyDesalinate
@MathiasR.Jessen thanks for your reply, it works !! Is it possible to do that also in the classic command prompt?Spaulding
No, not to my knowledge :)Desalinate
L
2

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 e.g.

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

Lineberry answered 30/5, 2022 at 13:17 Comment(7)
Thanks for your help! I really appreciate! how would you combine that path resolution with @mathies's comment? I mean: it just resolves the wildcards as you say, but does not execute the program called. And do you know if that is possible even without powershell?Spaulding
See edit @Spaulding and afaik not possible in the cmd promptLineberry
One last tip: how would you pass a complex command using this behavior, for example: more c:\windows\win.ini | findstr "fonts"Spaulding
Resolve-Path 'c:\w?ndows\win.ini' | gc | select-string 'fonts'Lineberry
In general Resolve-Path is a good tool to resolve wildcard paths. For the case of executing a program you don't need it though: & 'c:\wind?ws\n?tepad.exe' works perfectly fine.Cristophercristy
Thanks to both of you! I really appreciate your help! @Lineberry saldy your suggestion does not work. I tried this: & 'c:\wind?ws\System32\more.com' C:\Users\...\Desktop\something.txt | findstr "something" and it works. But how do I apply the same concept also to the arguments given?Spaulding
I think you’re struggling with mixing cmd and powershell. If using the latter, easier to use native cmdlets such as Get-Content rather than more and select-string rather than findstrLineberry
F
9
  • With limited exceptions in PowerShell, on Windows there is no support for shell-level globbing - target commands themselves must perform resolution of wildcard patterns to matching filenames; if they don't, globbing must be performed manually, up front, 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 (e.g., 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 globbing (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 (e.g. [ab]) and ranges (e.g. [0-9]); another important difference is that ? matches exactly one character, whereas the native file-system APIs - both on Windows and Unix-like platforms - match none or one.

        • However, when using the -Filter parameter of file-processing cmdlets such as Get-ChildItem, it is the host platform's file-system APIs that are used, which - while limiting features (as noted) - improves performance.
  • cmd.exe (Command Prompt, the legacy shell):

    • cmd.exe does not support calling executables by wildcard pattern; some of cmd.exe's internal commands (e.g., dir and del) and some standard external programs (e.g., 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 (e.g. 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; e.g., 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 (e.g., *.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; e.g.:

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

           & $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, and, conversely, the inability to individually `-escape wildcard metacharacters in order to suppress globbing - see GitHub issue #18038
          • The inability to include hidden files - see GitHub issue #4683.
Fierce answered 1/6, 2022 at 21:2 Comment(0)
L
2

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 e.g.

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

Lineberry answered 30/5, 2022 at 13:17 Comment(7)
Thanks for your help! I really appreciate! how would you combine that path resolution with @mathies's comment? I mean: it just resolves the wildcards as you say, but does not execute the program called. And do you know if that is possible even without powershell?Spaulding
See edit @Spaulding and afaik not possible in the cmd promptLineberry
One last tip: how would you pass a complex command using this behavior, for example: more c:\windows\win.ini | findstr "fonts"Spaulding
Resolve-Path 'c:\w?ndows\win.ini' | gc | select-string 'fonts'Lineberry
In general Resolve-Path is a good tool to resolve wildcard paths. For the case of executing a program you don't need it though: & 'c:\wind?ws\n?tepad.exe' works perfectly fine.Cristophercristy
Thanks to both of you! I really appreciate your help! @Lineberry saldy your suggestion does not work. I tried this: & 'c:\wind?ws\System32\more.com' C:\Users\...\Desktop\something.txt | findstr "something" and it works. But how do I apply the same concept also to the arguments given?Spaulding
I think you’re struggling with mixing cmd and powershell. If using the latter, easier to use native cmdlets such as Get-Content rather than more and select-string rather than findstrLineberry

© 2022 - 2024 — McMap. All rights reserved.