¿Por qué `dir *. *` Me da todos los archivos y carpetas?

62

Cuando lo ejecuto dir *.*produce resultados inesperados. Incluso se enumeran archivos y carpetas sin ningún punto en sus nombres. Por ejemplo

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

¿Porqué es eso? ¿Hay alguna manera de enumerar solo archivos con un punto?

phuclv
fuente
19
El punto siempre está ahí, simplemente no se imprime a menos que haya algo que lo siga. En otras palabras, puede pensar que un archivo se llama "este es mi archivo" pero en secreto el nombre es "este es mi archivo". sin nada después del punto. De manera análoga, podría pensar que el nombre DNS para este sitio es "superusuario.com", pero en realidad es "superusuario.com". sin nada después del segundo punto.
Todd Wilcox
12
@ToddWilcox solo es correcto en DOS. Los sistemas de archivos modernos en Windows ya no tienen un espacio de nombres de extensión separado
phuclv
13
@ LưuVĩnhPhúc El subsistema Win32 trata los nombres de archivo que no contienen un me .gusta que tienen .al final para muchos propósitos, incluido este.
CodesInChaos
2
Las carpetas que no contienen el .carácter tienen un .carácter implícito al final. - Puede tener una carpeta llamada "Blah.old", por ejemplo, y luego tendría una extensión de archivo tradicional de 3 letras; para el uso diario, aunque " Blah" es lo mismo que " Blah." ya sea un archivo o una carpeta.
BrainSlugs83
99
@ can-ned_food Todd Wilcox tiene razón sobre DNS. La zona DNS raíz se conoce literalmente ., y las etiquetas en los nombres DNS están separadas por .( por lo tanto, el nombre de la zona DNS raíz es una sola etiqueta de longitud cero). Un hijo de la zona DNS raíz .es com., y un hijo de com.es superuser.com., y así sucesivamente.
un CVn

Respuestas:

115

Estoy escribiendo esta respuesta porque OP ha enfatizado que:

lo que me interesa es por qué *.*coincide con todos los archivos, como se indica en la pregunta

El DIRcomando proviene de un momento en que:

  1. El punto (.) No se permitía como carácter en los nombres de archivo o carpeta
  2. Los nombres de archivos y carpetas se restringieron a 8 caracteres para el nombre y 3 caracteres para las extensiones

Por lo tanto, según ese estándar, *.*significaba cualquiera que sea el nombre y la extensión . No significaba una cadena que contenía un ".", Que puede tener o no caracteres antes o después del "." .

La política de Microsoft preserva la compatibilidad con versiones anteriores. Por lo tanto, esa interpretación de *.*se conserva.

Pero en Windows PowerShell, *.*significa una cadena que contiene un ".", Que puede tener o no caracteres antes o después del "." .

jpaugh
fuente
25
El sistema de archivos original ni siquiera almacenó el período en el disco, solo los 11 caracteres que componen el resto del nombre.
Sr. Lister
77
Vale la pena señalar que los archivos y carpetas sin extensiones todavía se tratan como si tuvieran una extensión en blanco . Por lo tanto, una carpeta llamada " Folder." y una carpeta llamada " Folder" se denominan de la misma manera, en lo que respecta a Windows.
BrainSlugs83
2
@MrLister Interesante. ¿Cómo almacenaban los antiguos nombres de archivos FS AA.BBcon <8 en la primera parte y <3 en la extensión? ¿Simplemente se rellena con espacios?
Kelvin
3
@ Kelvin, sí, las dos partes estaban separadas por espacio.
lavado el
12

¿Porqué es eso?

Uno podría encontrar una respuesta a " ¿Por qué es eso? " En el artículo sobre comodines :

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)

...

Reglas de coincidencia de comodines

  • *Generalmente coincide con 0 o más caracteres, con una excepción (ver la siguiente regla). El comodín no codicioso puede combinar tantos o tan pocos caracteres como sea necesario para que coincida el resto de la máscara.

  • *.Al final de la máscara coincide con 0 o más caracteres, excepto {dot}. En realidad, la regla se aplica con cualquier número de caracteres {dot} y {space} entre el * y el terminal {dot}. La expresión regular para este término es"[*][. ]*[.]$"

  • ?Haga coincidir 0 o un carácter, excepto {dot}. La única vez que coincide con 0 caracteres es cuando coincide con el final del nombre o la posición antes de un {punto}. El signo de interrogación también se puede usar más de una vez para unir más de un carácter.

Implicación . El último {punto} en un nombre de archivo / carpeta separa el nombre base y la extensión. Entonces

  • dir *.muestra todos los elementos sin extensión y
  • dir *.*Muestra todos los elementos con una extensión de cero o más caracteres .

Estrictamente hablando, dir *.muestra todos los elementos sin punto ( .) en el nombre . (BTW, Naming Files, Paths, and Namespaces El artículo de MSDN dice explícitamente que " es aceptable especificar un punto como primer carácter de un nombre ").

¿Hay alguna manera de enumerar solo archivos con un punto?

No lo creo. Sin embargo, hay una solución alternativa con una expresión regular adecuada.

PowerShell (solución de alcance completo si se usa en una consola Powershell):

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

Cmd (solo una idea, puede requerir alguna elaboración):

:: 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

Anexo: una bonificación y explicación

Una suposición intuitiva que Namese concatena BaseNamey Extension no se sostiene . La siguiente secuencia de comandos lo prueba con las características principales cmdy el uso PowerShell, y la extraña ^..*\...*$ expresión regular se deriva de sus resultados.

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

Salida :

==> 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 la definición de BaseNamepropiedad, diferente para archivos y carpetas:

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

Mi respuesta original se basó en un malentendido imperdonable:

Leer dir /?, usar 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

Otro enfoque: aplicar findstrregex comodir *.* | findstr /V "<.*>"

JosefZ
fuente
lo que me interesa es por qué *.*coincide con todos los archivos , como se indica en la pregunta
phuclv
Me temo que su sugerencia alternativa (FindStr) no encuentra carpetas que comienzan con un me .gusta .dbus-keyrings, .VirtualBoxy .vscode.
22
Entonces dir /A:-D, ¿ enumera solo los archivos que son felices?
Quentin
44
"¿Hay alguna forma de enumerar solo los archivos con un punto?" dir /A:-DEs incorrecto. 1 / enumera archivos sin extensión. 2 / no enumera los directorios que tienen un .nombre (perfectamente legal)
DavidPostill
3
Dios mío ... han pasado décadas desde la última vez que vi "@echo off"
rompe el
7

¿Hay alguna manera de enumerar solo archivos con un punto?

Puede hacer coincidir los nombres de archivo con un punto utilizando el comodín indocumentado <, que coincide con una secuencia de 0 o más caracteres en el nombre base o una secuencia de 0 o más caracteres en la extensión:

dir "<.<"

Recuerde que <también es un metacarácter, por lo que debe citarlo o escapar de él cada vez que lo use en un patrón desde el shell de comandos.

Feersum
fuente
1
excelente. Este comodín indocumentado sí existe
2017
1

El intérprete de línea de comandos verá " . " Como "Todos los nombres de archivo base" con "todas las extensiones". Una extensión en blanco sigue siendo una extensión , por lo que coincidirá y se devolverá con la lista. Como otros han explicado, esta es una resaca de versiones anteriores de Windows y MS-DOS.

Si está contento de mirar con PowerShell, encontrar estos archivos es mucho más fácil. Tenga en cuenta que en PowerShell, "dir" es un alias para el cmdlet "Get-ChildItem".

Para buscar todos los archivos (no directorios / carpetas) que tienen una extensión (por ejemplo, "myfile.txt", pero no "FileWithNoExt"):

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

el modificador "-af" es la abreviatura de "-File" que restringe los objetos devueltos a archivos solamente. "-ad" solo obtendría directorios. Los "\." significa "un carácter de punto literal". Sin la barra invertida, el punto coincidiría con cualquier carácter, según la expresión regular estándar.

Para obtener todos los archivos donde había un punto en el nombre sin la extensión, así como una extensión (por ejemplo, "myDocument_v1.1.doc" pero no "myfile.txt"):

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

Sin embargo, tenga en cuenta que esto excluirá un archivo con el nombre como ".archive" con un punto anterior. Esto se debe a que no se trata de tener un nombre base y una extensión de "archivo". Si desea incluir estos:

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

Aquí, el patrón de coincidencia dice "Un punto literal, OR (|) BeginningOfString (^) seguido de EndOfString ($) (es decir, una cadena vacía)". Como un archivo no puede tener un nombre de base y una extensión vacíos , encontrará los archivos que comienzan con un punto.

Dave_J
fuente
en PowerShell ls *.*es suficiente, como muchos otros han respondido antes que usted
phuclv
-2

Si escribe el comando anterior, entonces aquí: * (este es un comodín que significa cualquier secuencia de caracteres) seguido de un punto (.) Seguido de * esto podría interpretarse como mostrar todos los archivos que tienen un nombre como (cualquier secuencia de caracteres ). (cualquier secuencia de caracteres), lo que significa que muestra todos los archivos con cualquier extensión.

Rahul Kant
fuente
1
Entonces, ¿por qué está Program Filesincluido en la lista? No coincide con el patrón <sequence of characters>.<sequence of characters>.
gronostaj
Piénselo más como <Secuencia de cero o más caracteres> Es por eso que también seleccionaría un archivo llamado ".info" donde el nombre base está en blanco.
Dave_J