62

When I run dir *.* it produces unexpected results. Even files and folders without any dot in their names are listed. For example

C:\>dir *.*
 Volume in drive C is System
 Volume Serial Number is AC0A-29DA

 Directory of C:\

14-03-2017  05:17 PM             8,192 ntuser.dat
03-01-2017  07:10 PM    <DIR>          Perl520
28-03-2017  10:13 AM    <DIR>          Program Files
28-03-2017  10:13 AM    <DIR>          Program Files (x86)
04-01-2017  03:25 PM    <JUNCTION>     Python27 [C:\Program Files\Anaconda]
06-02-2017  10:16 PM    <DIR>          SAP
28-03-2017  04:10 PM               152 useragent.log
03-01-2017  03:04 PM    <DIR>          Users
16-03-2017  04:24 PM    <DIR>          VM
22-03-2017  11:13 AM    <DIR>          Windows
               2 File(s)          8,344 bytes
               8 Dir(s)  270,172,966,912 bytes free

Why is that? Is there any way to list only files with a dot?

10
  • 20
    The dot is always there, it's just not printed unless there is something following it. In other words, you might think a file is named "this is my file" but secretly the name is "this is my file." with nothing after the dot. Analogously, you might think that DNS name for this site is "superuser.com", but it's actually "superuser.com." with nothing after the second dot. Commented Mar 28, 2017 at 13:07
  • 12
    @ToddWilcox it's only correct in DOS. Modern filesystems in Windows don't have a separate extension namespace anymore
    – phuclv
    Commented Mar 28, 2017 at 15:55
  • 13
    @LưuVĩnhPhúc The Win32 subsystem treats filenames that don't contain a . like they have a . in the end for many purposes, including this one. Commented Mar 28, 2017 at 15:57
  • 2
    Folders that do not contain the . character have an implied . character at the end. -- You can have a have a folder named "Blah.old" for example, and then it would have a traditional 3 letter file extension; for day to day usage though "Blah" is the same as "Blah." whether it's a file or a folder. Commented Mar 29, 2017 at 1:19
  • 10
    @can-ned_food Todd Wilcox is correct about DNS. The root DNS zone is referred to as literally ., and labels in DNS names are separated by . (thus the name of the root DNS zone is a single zero-length label). One child of the root DNS zone . is com., and one child of com. is superuser.com., and so on.
    – user
    Commented Mar 29, 2017 at 8:04

5 Answers 5

114

I am writing this answer because OP has emphasized that:

what I'm interested is why *.* matches all files, as stated in the question

The DIR command comes from a time when:

  1. Period (.) was not allowed as a character in file or folder names
  2. File and folder names were restricted to 8 characters for name and 3 characters for extensions

Therefore, by that standard, *.* meant whatever the name and whatever the extension. It did not mean a string containing a ".", which may or may not have characters before or after the ".".

Microsoft policy is preserving backward compatibility. Hence, that interpretation of *.* is retained.

But in Windows PowerShell, *.* means a string containing a ".", which may or may not have characters before or after the ".".

11
  • 10
    Additional reading: blogs.msdn.microsoft.com/oldnewthing/20071217-00/?p=24143 Commented Mar 28, 2017 at 12:07
  • 25
    The original file system didn't even store the period itself on the disk, only the 11 characters making up the rest of the name.
    – Mr Lister
    Commented Mar 28, 2017 at 18:24
  • 8
    It's worth noting that files and folders without extensions are still treated as having a blank extension. Therefore, a folder named "Folder.", and a folder named "Folder" are named the same thing, as far as windows is concerned. Commented Mar 29, 2017 at 1:23
  • 2
    @MrLister Interesting. How did the old FS store file names like AA.BB with < 8 in the first part and < 3 in the extension? Did it just pad with spaces?
    – Kelvin
    Commented Mar 29, 2017 at 17:02
  • 3
    @Kelvin yes the two parts were seperately space-padded.
    – plugwash
    Commented Mar 29, 2017 at 17:42
11

Why is that?

One could find an answer to "Why is that?" in Wildcards article:

The * wildcard will match any sequence of characters
               (0 or more, including NULL characters)

The ? wildcard will match a single character
               (or a NULL at the end of a filename)

Wildcard matching rules

  • * Generally matches any 0 or more characters, with one exception (see next rule). The non-greedy wildcard is free to match as many or as few characters as are necessary for the remainder of the mask to match.

  • *. At end of mask matches any 0 or more characters except for {dot}. In actuality, the rule applies with any number of {dot} and {space} characters between the * and terminal {dot}. The regular expression for this term is "[*][. ]*[.]$"

  • ? Match 0 or one character, except for {dot}. The only time it matches 0 characters is when it matches the end of the name, or the position before a {dot}. The question mark can also be used more than once to match more than one character.

Implication. The last {dot} in a file/folder name separates base name and extension. So

  • dir *. displays all items with no extension, and
  • dir *.* displays all items with extension of zero or more characters.

Strictly speaking, dir *. displays all items with no period (.) in name. (BTW, Naming Files, Paths, and Namespaces MSDN article says explicitly that "it is acceptable to specify a period as the first character of a name".)

Is there any way to list only files with a dot?

I don't think so. However, there is a workaround with a fitting regular expression.

PowerShell (full scope solution if used in a Powershell console):

:: PowerShell - no extension, full syntax
PowerShell -c "Get-ChildItem | Where-Object {$_.Name -match '^.[^\.]*$'}"
:: PowerShell -    extension, alias syntax
PowerShell -c "dir | ? {$_.Name -match '^..*\...*$'}"

Cmd (an idea only, might require some elaboration):

:: CMD/batch - no extension
for /F "delims=" %%G in ('dir /OGN /B ^| findstr "^.[^\.]*$"') do @echo %%~tG %%~aG %%~zG %%~nxG
:: CMD/batch -    extension
for /F "delims=" %%G in ('dir /OGN /B ^| findstr "^..*\...*$"') do @echo %%~tG %%~aG %%~zG %%~nxG

Addendum: a bonus and explanation

An intuitive guess that Name is concatenated BaseName and Extension does not hold. The following script proves it using cmd and PowerShell core features, and the weird ^..*\...*$ regex is derived from it's results.

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_workingDirectory=%~1"
if "%_workingDirectory%"=="%tmp%\tests_SU_1193102" (
  >NUL 2>&1 (
      mkdir "%_workingDirectory%"
      pushd "%_workingDirectory%"
      rem make directories
      mkdir     .Fldr-Ext
      mkdir     aFldr-Ext
      mkdir     .Fldr.Ext
      mkdir     aFldr.Ext
      rem create files
      copy  NUL .File-Ext 
      copy  NUL aFile-Ext 
      copy  NUL .File.Ext 
      copy  NUL aFile.Ext
      popd
  )
) else if "%_workingDirectory%"=="" set "_workingDirectory=%CD%"
pushd "%_workingDirectory%"
set "_first=ItemName  Attributes    BaseName Extension"
echo ON
::                        dir /OGN | findstr "Ext$"
for /F "delims=" %%G in ('dir /OGN /B') do @((if defined _first (echo %_first%&echo(&set "_first="))&echo %%~nxG %%~aG  %%~nG   %%~xG)
::   Get-ChildItem | Select-Object -Property Mode, BaseName, Extension, Name
PowerShell -c "dir | select -pr Name, Mode, BaseName, Extension | sort -pr @{Expression='Mode';Descending=$true}, @{Expression='Name';Descending=$false}"

Output:

==> D:\bat\BaseName_vs_Extension.bat "%tmp%\tests_SU_1193102"

==> for /F "delims=" %G in ('dir /OGN /B') do @((if defined _first (echo ItemName  Attributes   BaseName Extension  & echo(  & set "_first=" ) )  & echo %~nxG %~aG     %~nG    %~xG )
ItemName  Attributes    BaseName Extension

.Fldr.Ext d----------   .Fldr   .Ext
.Fldr-Ext d----------           .Fldr-Ext
aFldr.Ext d----------   aFldr   .Ext
aFldr-Ext d----------   aFldr-Ext
.File.Ext --a--------   .File   .Ext
.File-Ext --a--------           .File-Ext
aFile.Ext --a--------   aFile   .Ext
aFile-Ext --a--------   aFile-Ext

==> PowerShell -c "dir | select -pr Name, Mode, BaseName, Extension | sort -pr @{Expression='Mode';Descending=$true}, @{Expression='Name';Descending=$false}"

Name      Mode   BaseName  Extension
----      ----   --------  ---------
.Fldr.Ext d----- .Fldr.Ext .Ext
.Fldr-Ext d----- .Fldr-Ext .Fldr-Ext
aFldr.Ext d----- aFldr.Ext .Ext
aFldr-Ext d----- aFldr-Ext
.File.Ext -a---- .File     .Ext
.File-Ext -a----           .File-Ext
aFile.Ext -a---- aFile     .Ext
aFile-Ext -a---- aFile-Ext

Compare definition of BaseName property, different for files and folders:

PS D:\PShell> Get-ChildItem | Get-Member -Name BaseName | Format-List -property TypeName, Definition


TypeName   : System.IO.DirectoryInfo
Definition : System.Object BaseName {get=$this.Name;}

TypeName   : System.IO.FileInfo
Definition : System.Object BaseName {get=if ($this.Extension.Length -gt 
             0){$this.Name.Remove($this.Name.Length - 
             $this.Extension.Length)}else{$this.Name};}

My original answer was based on unforgivable misunderstanding:

Read dir /?, use dir /A:-D:

/A          Displays files with specified attributes.
attributes   D  Directories                R  Read-only files
             H  Hidden files               A  Files ready for archiving
             S  System files               I  Not content indexed files
             L  Reparse Points             -  Prefix meaning not

Another approach: apply findstr regex as dir *.* | findstr /V "<.*>"

8
  • what I'm interested is why *.* matches all files, as stated in the question
    – phuclv
    Commented Mar 28, 2017 at 10:35
  • I am afraid your alternative suggestion (findstr) does not find folders that start with a . like .dbus-keyrings, .VirtualBox and .vscode.
    – user477799
    Commented Mar 28, 2017 at 10:39
  • 23
    So dir /A:-D lists only files that are happy?
    – Quentin
    Commented Mar 28, 2017 at 11:55
  • 4
    "Is there any way to list only files with a dot?" dir /A:-D is incorrect. 1/ it lists files with no extension. 2/ it doesn't list directories that have a . in their name (perfectly legal)
    – DavidPostill
    Commented Mar 28, 2017 at 15:41
  • 3
    omg ... it's been decades since I last saw "@echo off"
    – rupps
    Commented Mar 29, 2017 at 20:09
6

Is there any way to list only files with a dot?

You can match filenames with a dot by using the undocumented wildcard <, which matches either a sequence of 0 or more characters in the basename or a sequence of 0 or more characters in the extension:

dir "<.<"

Remember that < is also a metacharacter, so you need to quote or escape it whenever using it in a pattern from the command shell.

1
1

The Command Line Interpreter will see "." as "All base filenames" with "all extensions". A blank extension is still an extension, so will be matched and returned with the list. As others have explained, this is a hangover from earlier versions of Windows and MS-DOS.

If you're happy to look using PowerShell, finding these files is a lot easier. Note that in PowerShell, "dir" is an alias for the "Get-ChildItem" cmdlet.

To find all files (not directories/folders) that have an extension (e.g. "myfile.txt", but not "FileWithNoExt"):

dir -af | Where {$_.Name -match "\."}

the "-af" switch is shorthand for "-File" which restricts the return objects to files only. "-ad" would only get directories. The "\." means "a literal dot character". Without the backslash, the dot would match any character, as per standard regex.

To get all files where there was a dot in the name without the extension, as well as an extension (e.g. "myDocument_v1.1.doc" but not "myfile.txt"):

dir -af | Where {$_.BaseName -match "\."}

Note however, that this will exclude a file with the name such as ".archive" with a preceding dot. This is because it's treated as having no basename and an extension of "archive". If you want to include these:

dir -af | Where {$_.BaseName -match "\.|^$"}

Here, the match pattern says "A literal dot, OR(|) BeginningOfString(^) followed by EndOfString($) (i.e. an empty string)". Since a file can't have both an empty basename and extension, it will find the files starting with a dot.

1
  • in PowerShell just ls *.* is enough, as many others have answered before you
    – phuclv
    Commented Sep 28, 2018 at 4:16
-2

If you type above command, then here: * (this is a wild card which means any sequence of characters) followed by a dot(.) followed by * this could be interpreted as show all files which have name like (any sequence of characters).(any sequence of characters) which further means that show all files with any extension.

2
  • 1
    Then why is Program Files included in the list? It doesn't match the pattern <sequence of characters>.<sequence of characters>.
    – gronostaj
    Commented Mar 30, 2017 at 8:34
  • Think of it more as <Sequence of zero or more characters> It's why it would also pick up a file called ".info" where the base name is blank.
    – Dave_J
    Commented Mar 30, 2017 at 11:05

You must log in to answer this question.

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