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'
CodePudding user response:
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')
CodePudding user response:
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.
- Generally, you can discover commands, including external programs, via the
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 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.)
- While
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 thecmd.exe
'secho
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 on Windows match none or one.- However, when using the
-Filter
parameter of file-processing cmdlets such asGet-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, i.e causing it to match none or one character.
- However, when using the
cmd.exe
(Command Prompt, the legacy shell):cmd.exe
does not support calling executables by wildcard pattern; some ofcmd.exe
's internal commands (e.g.,dir
anddel
) 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 thePATH
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 offor
statements (whose wildcard matching has the same limitations as thedir
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 asGet-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 withexp
, such asexplorer
.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.
- 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
- However, this emulation has limitations, as of PowerShell 7.2.4: