web-dev-qa-db-fra.com

Pourquoi `dir *. *` Me donne-t-il tous les fichiers et dossiers?

Lorsque je lance dir *.*, cela produit des résultats inattendus. Même les fichiers et les dossiers sans nom dans leur nom sont répertoriés. Par exemple

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

Pourquoi donc? Est-il possible de ne lister que les fichiers avec un point?

62
phuclv

J'écris cette réponse parce que OP a souligné que:

ce qui m'intéresse est pourquoi *.* correspond à tous les fichiers, comme indiqué dans la question

La commande DIR vient d'un moment où:

  1. Le point (.) N'était pas autorisé en tant que caractère dans les noms de fichiers ou de dossiers
  2. Les noms de fichiers et de dossiers étaient limités à 8 caractères pour le nom et à 3 caractères pour les extensions.

Par conséquent, selon cette norme, *.* signifiait quels que soient le nom et l’extension . Cela ne voulait pas dire une chaîne contenant un ".", Qui peut avoir ou non des caractères avant ou après le "." .

La politique de Microsoft préserve la compatibilité ascendante. Par conséquent, cette interprétation de *.* est conservée.

Mais dans Windows PowerShell, *.* signifie une chaîne contenant un ".", Qui peut contenir ou non des caractères avant ou après le "." .

115
user477799

Pourquoi donc?

On pourrait trouver une réponse à "Pourquoi est-ce que c'est?" Dans 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)

Règles de correspondance générique

  • * Correspond généralement à 0 caractère ou plus, à une exception près (voir la règle suivante). Le caractère générique non gourmand est libre de faire correspondre le nombre de caractères nécessaire pour que le reste du masque corresponde.

  • *. À la fin du masque correspond à 0 caractère ou plus, à l'exception de {point}. En réalité, la règle s'applique avec un nombre quelconque de caractères {point} et {espace} entre le * et le terminal {point}. L'expression régulière pour ce terme est "[*][. ]*[.]$"

  • ? Match 0 ou un caractère, sauf pour {dot}. La seule fois où il correspond à 0 caractère, c'est lorsqu'il correspond à la fin du nom ou à la position précédant un {point}. Le point d'interrogation peut également être utilisé plusieurs fois pour faire correspondre plusieurs caractères.

Implication. Le dernier _ {point} d'un nom de fichier/dossier sépare nom de base et extension. Alors

  • dir *. affiche tous les éléments avec pas d’extension , et
  • dir *.* affiche tous les éléments avec extension de zéro caractère ou plus .

À proprement parler, dir *. affiche tous les éléments avec sans période (.). (BTW, Nommer des fichiers, des chemins et des espaces de noms MSDN article dit explicitement que "il est acceptable de spécifier un point comme premier caractère d'un nom}". "

Est-il possible de ne lister que les fichiers avec un point?

Je ne pense pas. Toutefois, il existe une solution de contournement avec une expression régulière appropriée.

PowerShell (solution complète si elle est utilisée dans une console Powershell):

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

Cmd (une idée seulement, peut nécessiter quelques explications):

:: 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: un bonus et une explication

Une hypothèse intuitive selon laquelle Name est concaténée BaseName et Extension ne tient pas . Le script suivant le prouve en utilisant cmd et PowerShell, et le regex bizarre^..*\...*$ est dérivé de ses résultats.

@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}"

Sortie :

==> 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 définition de la propriété BaseName, différente pour les fichiers et les dossiers:

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};}

Mon réponse originale était basé sur un malentendu impardonnable:

Lisez dir /?, utilisez 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

Une autre approche: apply findstr regex as dir *.* | findstr /V "<.*>"

12
JosefZ

Est-il possible de ne lister que les fichiers avec un point?

Vous pouvez faire correspondre les noms de fichiers avec un point en utilisant le caractère générique non documenté <, qui correspond à une séquence de 0 caractères ou plus dans le nom de base ou à une séquence de 0 caractères ou plus dans l'extension:

dir "<.<"

N'oubliez pas que < est également un métacaractère. Vous devez donc le citer ou l'échapper si vous l'utilisez dans un motif de la commande Shell.

6
feersum

L'interpréteur de ligne de commande verra ". " comme "Tous les noms de fichiers de base" avec "toutes les extensions". Une extension vide est est toujours une extension , elle sera donc mise en correspondance et retournée à la liste. Comme d'autres l'ont expliqué, il s'agit d'une survivance de versions antérieures de Windows et de MS-DOS.

Si vous préférez utiliser PowerShell, il est beaucoup plus facile de rechercher ces fichiers. Notez que dans PowerShell, "dir" est un alias de la cmdlet "Get-ChildItem".

Pour rechercher tous les fichiers (pas les répertoires/dossiers) ayant une extension (par exemple, "myfile.txt", mais pas "FileWithNoExt"):

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

le commutateur "-af" est un raccourci pour "-Fichier" qui limite les objets renvoyés aux fichiers. "-ad" n'obtiendrait que des répertoires. Le "\." signifie "un caractère littéral". Sans la barre oblique inverse, le point correspondrait à n'importe quel caractère, comme dans les expressions rationnelles standard.

Pour obtenir tous les fichiers contenant un point dans le nom sans l'extension, ainsi qu'une extension (par exemple, "myDocument_v1.1.doc" mais pas "myfile.txt"):

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

Notez cependant que cela exclura un fichier avec le nom tel que ".archive" avec un point précédent. Ceci est dû au fait qu'il est traité comme n'ayant pas de nom de base et une extension "archive". Si vous souhaitez inclure ces éléments:

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

Ici, le motif de correspondance indique "Un point littéral, OU (|) BeginningOfString (^) suivi de EndOfString ($) (c'est-à-dire une chaîne vide)". Comme un fichier ne peut pas avoir à la fois une extension vide - et , il trouvera les fichiers commençant par un point.

1
Dave_J