Is there any way to get the windows cmd shell to expand wildcard paths?
DOS, and consequently Windows' cmd.exe
, never supported wildcard expansion by the shell. It was always up to the application to do the expansion.
This means you will always have to find another route if you're using an application that doesn't support expansion. You could:
- Use a FOR loop to run some commands against all the files you're interested in
- Use
dir /b > list.txt
to use thedir
command to perform the expansion and put the list of files into a text file (you could then use something like an Excel formula if you're really desperate to produce a list of commands to paste intocmd
, or you could use Excel to transpose the cells so all the filenames are on the same line.)
This will give you a list and also put it in variable named expanded_list
. Put it in batch file and run with myBatchFile name myPattern
. Enclose pattern with quotation marks if it includes spaces. Matches files, no dirs. Run without parameters matches all.
@echo off
set expanded_list=
for /f "tokens=*" %%F in ('dir /b /a:-d "%~1"') do call set expanded_list=%%expanded_list%% "%%F"
echo expanded_list is:
echo %expanded_list%
You can then run you command with my_command_exec %expanded_list%
WARNING! Maximum size of cmd variable is 8191 characters (XP onwards), so it's possible to overflow it! You cannot count on the utility to always give you complete list. On the other hand, maximum cmd line length is also 8191 so you would not be able to execute it anyway.
Just use Powershell, which is preinstalled on Windows 7. Powershell is capable of running cmd commands and does understand wildcards at any place in a path.
To start Powershell just type "powershell" in your start menu search box and hit enter.
In case the application expects a string with all filenames in it this is the right script:
$delimiter = " "
[string]$files = $nothing ; ls *.txt | % { $files += $_.fullname + $delimiter } ; application.exe $files
Change $delimiter = " "
to $delimiter = ","
if your application expects a comma separated list of file names.
Explanation of code:
-
[string]$files = $nothing
- creates an empty variable of typestring
-
;
- is a separator for multiple commands, not a pipeline! -
ls *.txt | % { $files += $_.fullname + $delimiter }
- gets a list of all text files and creates a string with all filenames separated by the delimiter -
application.exe $files
- calls the application and passes the file list to it
You can even search for a file pattern recursively by adding -recurse
to ls *.txt
so the complete code would look like this:
$delimiter = " "
[string]$files = $nothing ; ls *.txt -recurse | % { $files += $_.fullname + $delimiter } ; application.exe $files
Edit:
To avoid irritations, ls
and dir
are aliases of Get-ChildItem
and %
is an alias to ForEach-Object
. I keep my code with aliases used because it's shorter.
EDIT 2018/04/25:
Back in 2012 I've been fairly new to PowerShell. Of course there is an easier way though it's not as easy as unix/linux' capability of glob expansion:
app.exe $(ls *.txt | % {$_.FullName})
Explanation:
- $() will evaluate the expression inside first and will replace itself with the output of that expression (much like backticks do in bash)
-
ls *.txt
gets FileInfo objects of all files that match the glob*.txt
- because PowerShell is object oriented, we have to output the
fullname of each FileInfo object. Simply naming an attribute/property
in PowerShell outputs it by default.
% { $_.FileName }
does that for us.%
loops over all elements returned byls
and outputs each objects FileName.