Why does `dir *.*` give me all files and folders?

10,091

Solution 1

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 ".".

Solution 2

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 "<.*>"

Solution 3

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.

Solution 4

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.

Share:
10,091

Related videos on Youtube

phuclv
Author by

phuclv

Normal user, not super

Updated on September 18, 2022

Comments

  • phuclv
    phuclv almost 2 years

    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?

    • Todd Wilcox
      Todd Wilcox about 7 years
      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.
    • phuclv
      phuclv about 7 years
      @ToddWilcox it's only correct in DOS. Modern filesystems in Windows don't have a separate extension namespace anymore
    • CodesInChaos
      CodesInChaos about 7 years
      @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.
    • BrainSlugs83
      BrainSlugs83 about 7 years
      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.
    • can-ned_food
      can-ned_food about 7 years
      @ToddWilcox Erm, I think that's really mixing a few things. So far as I know, the bit about the DNS lookup is also incorrect. I think most of them perform a simple rule-based redirect if you query for a hostname like that.
    • user
      user about 7 years
      @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.
    • Beesu Ravindar Reddy
      Beesu Ravindar Reddy about 7 years
      Note that, in Windows, the parsing of wildcards is the responsibility of the command, not the Command Prompt. As such, the expansion rules for one command-line tool might be different from another's. This is different to -- say -- Linux, where the shell is usually responsible (subject to quoting). That said, Command Prompt's built-in commands (including dir, copy, del, etc) tend to have the same expansion rules (as they are all implemented within the same program -- the Command Prompt).
    • Justin Time - Reinstate Monica
      Justin Time - Reinstate Monica about 7 years
      Interestingly, in at least one version of MS-DOS (MS-DOS 7.1, included with Windows 95 OEM Service Release 2 or later, and all versions of Windows 98), the command dir.exe (for example) is parsed as dir *.exe; this behaviour doesn't seem to be present in the Windows NT Command Prompt, as far as I can tell.
    • Medinoc
      Medinoc about 7 years
      @jimbobmcgee The Windows API handles the wildcard expansion with its FindFirstFile function family (and its wrapper family _findfirst in the C Run-Time library), so any program that uses it will have the same wildcard expansion.
    • TecBrat
      TecBrat about 7 years
      This info comes in handy when trying to save .htaccess from notepad.exe on Windows. Or any other dot file
  • phuclv
    phuclv about 7 years
    what I'm interested is why *.* matches all files, as stated in the question
  • Admin
    Admin about 7 years
    I am afraid your alternative suggestion (findstr) does not find folders that start with a . like .dbus-keyrings, .VirtualBox and .vscode.
  • Quentin
    Quentin about 7 years
    So dir /A:-D lists only files that are happy?
  • user1686
    user1686 about 7 years
  • DavidPostill
    DavidPostill about 7 years
    "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)
  • Mr Lister
    Mr Lister about 7 years
    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.
  • BrainSlugs83
    BrainSlugs83 about 7 years
    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.
  • can-ned_food
    can-ned_food about 7 years
    @LưuVĩnhPhúc the incorrect bits of this question aside, it does go for primarily answering the functional part of your question — the “Is there any way” — which is what I'd expect would be your primary concern; the “why” in your title almost seems superfluous.
  • phuclv
    phuclv about 7 years
    @can-ned_food that's a minor thing I want to know, as the consequence of the command's result. What I'm asking is the bold text on top of this page
  • phuclv
    phuclv about 7 years
    dir *. displays all files and folders with no extension, not only folders. dir *.* also list files and folders
  • wizzwizz4
    wizzwizz4 about 7 years
    @BrainSlugs83 Well, it depends which part of Windows. I had a nasty bug where I saved a file from IE11 with a . at the end of its name. I've no clue what the sysadmins did to fix it, but any action on the file. file by Windows Explorer was attempted on file instead, thus preventing me from deleting the entire directory tree. They probably used Powershell, because (as shown in this answer) that doesn't have the caveats-in-the-name-of-compatibility that much of Windows does.
  • Kelvin
    Kelvin about 7 years
    @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?
  • plugwash
    plugwash about 7 years
    @Kelvin yes the two parts were seperately space-padded.
  • Mr Lister
    Mr Lister about 7 years
    @Kelvin Yes. Like AA␣␣␣␣␣␣BB␣
  • rupps
    rupps about 7 years
    omg ... it's been decades since I last saw "@echo off"
  • TripeHound
    TripeHound about 7 years
    @Kelvin If you're interested in all the (old) gory details, see pages 6/7 of this PDF
  • gronostaj
    gronostaj about 7 years
    Then why is Program Files included in the list? It doesn't match the pattern <sequence of characters>.<sequence of characters>.
  • Dave_J
    Dave_J about 7 years
    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.
  • DavidPostill
    DavidPostill about 7 years
    @BrainSlugs83 Not so. i.imgur.com/710MUG7.png
  • Ross Presser
    Ross Presser about 7 years
    @DavidPostill But see: imgur.com/UgmX8xi They are the same for some purposes and not the same for others.
  • phuclv
    phuclv about 7 years
    excellent. This undocumented wildcard does indeed exist
  • Thorbjørn Ravn Andersen
    Thorbjørn Ravn Andersen about 7 years
    All this was originally done to emulate CP/M which did the exact same thing. This was then reworked in MS-DOS 2 to give something much closer to what we know today. This is also the reason that \ is used instead of / as in Unix, because / was already taken in CP/M to indicate command line options.
  • phuclv
    phuclv over 5 years
    in PowerShell just ls *.* is enough, as many others have answered before you