50

Occasionally, the cmd shell's inability to expand wildcard paths can really be an inconvenience. I had to pass 100 files in a directory to a program, and couldn't type *.ext. Instead, I used mingw's 'ls' to dump the list to a file, then replaced newlines with spaces, copied and pasted into cmd. Quite a nightmare.

I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier?

4
  • 3
    Have you considered using something like Powershell instead?
    – user3463
    Aug 12, 2012 at 6:33
  • I suspect the answer will be no, but has anyone dealt with this or come up with any way to make this easier? Actually, I’m having the opposite problem, I am trying to figure out a way to get the command-interpreter to treat its list as strings and prevent it from inreptreting them as wildcards. For example, for %i in (foobar baz really?) do @echo %i will treat the last item (really?) as a filename wildcard, and skip it if there are no files named really1, reallyz, etc. ☹
    – Synetech
    Feb 4, 2013 at 18:19
  • 3
    @Synetech - ? is not a legal character for filenames in the Windows filesystem. The character can only be interpreted as a wildcard. See Naming Files, Paths, and Namespaces on MSDN and Using wildcard characters in TechNet.
    – jww
    Jul 29, 2015 at 4:33
  • 1
    Are you trying to get a list of files in some directory separated by spaces?
    – Zimba
    May 9, 2020 at 14:22

8 Answers 8

26

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 the dir 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 into cmd, or you could use Excel to transpose the cells so all the filenames are on the same line.)
7
  • He explained that it would be a nightmare to output results of dir into a file and process filtering and copying manually. wmz's answer and of course mine would work without manually filtering a files content.
    – wullxz
    Aug 13, 2012 at 2:51
  • 1
    @wullxz: Perhaps, but for someone unfamiliar with Powershell wanting to do this as a one-off, it could be considerably faster - and the idea behind this site is to provide useful solutions for people of all skill levels to refer to now and in the future, so really there's no need to tell me off because you think my answer isn't as good as yours.
    – Malvineous
    Aug 14, 2012 at 8:07
  • 1
    "DOS, and consequently Windows' cmd.exe, never supported wildcard expansion by the shell." - Not true according to Microsoft. See Using wildcard characters on TechNet. (But I think you are right in practice :o. Otherwise, I would not be here trying to figure out why files are not matched)
    – jww
    Jul 29, 2015 at 4:30
  • 1
    @jww: The link you posted explains the standard use of the wildcard characters, but I can't see any mention of them being expanded by the shell. Unlike UNIX (and later Linux and Mac), Microsoft left wildcard expansion up to each individual application to implement, passing the command line parameters through as-is.
    – Malvineous
    Jul 30, 2015 at 3:59
  • 1
    DOS command 'dir Filespec /b' works really well, because it creates a list of files, one per line. With the additional '/s' switch, the file names are fully qualified (absolute), and can easily be fed through a for loop to any other command line program that takes a file name. It's the best we can do, since Windows doesn't have a proper globbing feature. Apr 23, 2018 at 21:39
12

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 type string
  • ; - 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 by ls and outputs each objects FileName.
13
  • 3
    Alhough PS is certainly capable to fulfill the reqest and the advice to familiarize with it is sound - it's not as simple as you suggest. Running start notepad++ *.txt (with intention to open all textfiles - used notepad++ as it does handle multiple names) will get you nowhere
    – wmz
    Aug 12, 2012 at 12:43
  • 1
    You could workaround that with dir *.txt | % { notepad++.exe $_ }. I tried that with simple notepad, because I don't have notepad++, and it worked. The command receives a list of all txt files in the current directory, passes the list on to the next command which loops through the list and executes notepad++ with the filename as parameter.
    – wullxz
    Aug 12, 2012 at 12:49
  • yes, but this is not equivalent. Think about grep "a b c" to find any of listed strings, where "a b c" would be expanded list
    – wmz
    Aug 12, 2012 at 13:42
  • 7
    Running a command with a list of items as parameter is not equivalent to running command multiple times with each element from a list as a parameter. Another example: copy a+b+c result and copy a result copy b result copy c result. (and grep like utility do exists in PS, it's called select-string)
    – wmz
    Aug 12, 2012 at 14:14
  • 1
    upvoted, btw it's a pity that OP does not care to chime in to explain...
    – wmz
    Aug 13, 2012 at 9:47
11

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.

2
  • Note if no arguments are specified then expanded_list will be set to all files in the current directory which may or may not be what is wanted so might want add check for no arguments (e.g. if "%1"=="" ...)
    – CodeMonkey
    Feb 27, 2014 at 19:04
  • You don't need /f and dir, just for %%f in ("%~1") ... OTOH do call instead of delayedexpansion is a neat trick. May 1, 2022 at 11:57
5

Note, this is in Comment to the posters in a separate thread user619818 and styfle)

DIR can and does allow searching all subdirectories for files matching a specific type.

Note: The Root Directory to check which all subdirectories lie under is assumed to be "C:\My Program\Root" as the author did not give a path name under which these directories are located

DIR /B /S "C:\My Program\Root\*.ext"

this will give the full file paths and filenames of the source files.

if you only want file names you would have to do as follows

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( Echo.%~nxA )

so assuming you want to move all of these files from "C:\My Program\Root\Sub Directories\.ext" to "D:\Singlefolder\.ext" you simply do this:

FOR /F "Tokens=*" %A IN ('DIR /B /S "C:\My Program\Root\*.ext"') DO @( MOVE "%~A" "D:\Singlefolder\%~nxA" /Y )

Hope that helps others in the future. :)

2
  • You don't need dir; for /r %f in (\path\*.ext) do @echo %f (or %~nf etc) searches subdirectories, which OP didn't ask for. But it doesn't pass the list as arguments to a program, which OP did want. May 1, 2022 at 11:48
  • @dave_thompson_085 The answer given was in response to another answer (as noted at the top) when I was a new member who could not comment, but could leave an answer (kinda backwards of SE IMHO) so was only addressing their comments about dir in a for loop with a file glob. May 10, 2022 at 15:57
3

This works in cmd.exe

dir /b *.ext

or

echo | dir /b *.ext
3
  • This only works for the file name, not any part of the path. For example dir /b TortoiseSVN\bin\sv*.exe will show svn.exe and svnadmin.exe. But dir /b TortoiseSVN\bi*\svn.exe shows a syntax error.
    – styfle
    Sep 11, 2015 at 19:26
  • 1
    check dir /s /b. This gives you the full path.
    – WesternGun
    May 27, 2019 at 9:47
  • @WesternGun: but it alo includes subdirectories to any level, which OP didn't ask for. May 1, 2022 at 11:48
2

This is old, but with the Linux subsystem for windows, its pretty common to have bash in your PATH now. If that is the case, then this might do the trick for you:

bash -c 'cat *.txt'
2
  • note that single quotes are not special in Windows cmd, thus if you run the above command from cmd it won't work. And this also applies to systems with Cygwin or other bash environments
    – phuclv
    Aug 30, 2018 at 4:04
  • @phuclv: CMD doesn't treat singlequotes as special, but it also doesn't expand wildcards (the point of this Q), so this passes the command unchanged to WSL (or cygwin etc) which DOES handle singlequotes and it DOES work. May 1, 2022 at 11:50
0

Why not for loop to pass the list of files to the program:

for %i in (*.txt) do start notepad %i

Or if you want to pass all files (list) to run one instance of the program (eg. pass a list of files separated by spaces):

set list=.& (for %i in (*.txt) do set list=!list! %i)& start app.exe !list:~2!

In 2nd case, the list variable contains all the files represented by *.txt:

echo !list:~2!

If the program can't detect filenames with spaces, then quote the names:

set list=.& (for %i in (*.txt) do set list=!list! "%i")& start app.exe !list:~2!

Tested in Win CMD

0

There is a really simple solution to this given by Microsoft: https://docs.microsoft.com/en-us/cpp/c-language/expanding-wildcard-arguments?view=msvc-170

Basically, you just link with one of two libraries that will expand wildcards into the argv[] list fed to your program.

To clarify by example, say you have the code:

// ExampleFileExpansion.cpp : This outputs the cmd line arguments
//

#include <iostream>
#include <tchar.h>

using namespace std;

int wmain(int argc, _TCHAR* argv[]) {
    for (int i = 0; i < argc; i++) {
        wcout << i << "\t" << argv[i] << endl;
    }
}

Which normally gives output like:

C:\x64\Debug>ExampleFileExpansion *.*

0       ExampleFileExpansion
1       *.*

Within Visual Studio, navigate to the project properties page and choose the linker input options | Additional Dependencies. Then, add the library (in this case "wsetargv.obj") and apply the change. Then, Build the project again, from the main menu.

After the change, running the same code gives something like:

C:\x64\Debug>ExampleFileExpansion *.*

0       ExampleFileExpansion
1       ExampleF.a660785c.tlog
2       ExampleFileExpansion.exe
3       ExampleFileExpansion.exe.recipe
4       ExampleFileExpansion.ilk
5       ExampleFileExpansion.log
6       ExampleFileExpansion.obj
7       ExampleFileExpansion.pdb
8       ExampleFileExpansion.vcxproj.FileListAbsolute.txt
9       vc143.idb
10      vc143.pdb

Here are some screen shots from VS 2022 to illustrate the steps:

Visual Studio Project Properties Menu

Choose Linker input options, then Edit to get the dialog

Enter the appropriate obj file name either wsetargv.obj or setargv.obj depending on whether wmain or main function is declared

3
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Feb 26, 2022 at 18:33
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - From Review Feb 26, 2022 at 19:41
  • Sure, sorry. Let me work out an example and I'll post it. I was looking for the answer to the same question and when I found this, it was so elegant I thought I'd just share what I found. Feb 27, 2022 at 19:31

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .