Por que o `dir *. *` Me fornece todos os arquivos e pastas?

61

Quando eu corro dir *.*, produz resultados inesperados. Mesmo arquivos e pastas sem qualquer ponto em seus nomes são listados. Por exemplo

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

Por que é que? Existe alguma maneira de listar apenas arquivos com um ponto?

phuclv
fonte
18
O ponto está sempre lá, não é impresso a menos que haja algo seguindo-o. Em outras palavras, você pode pensar que um arquivo é chamado "este é o meu arquivo", mas secretamente o nome é "este é o meu arquivo". sem nada depois do ponto. Analogamente, você pode pensar que o nome DNS para este site é "superuser.com", mas na verdade é "superuser.com". sem nada depois do segundo ponto.
Todd Wilcox
12
@ToddWilcox está correto apenas no DOS. Sistemas de arquivos modernos no Windows não têm mais um namespace de extensão separado
phuclv
13
@ LưuVĩnhPhúc O subsistema Win32 trata nomes de arquivos que não contêm um .como se tivessem um .no final para muitos propósitos, incluindo este.
CodesInChaos
2
As pastas que não contêm o .caractere têm um .caractere implícito no final. - Você pode ter uma pasta chamada "Blah.old" por exemplo, e então ela teria uma extensão de arquivo de 3 letras tradicional; para uso do dia a dia " Blah" é o mesmo que " Blah." se é um arquivo ou uma pasta.
BrainSlugs83
9
@ can-ned_food Todd Wilcox está correto sobre o DNS. A zona DNS raiz é chamada literalmente .e os rótulos nos nomes DNS são separados por .(assim, o nome da zona DNS raiz é um único rótulo de comprimento zero). Um filho da zona DNS raiz .é com.e um filho de com.is superuser.com.e assim por diante.
um CVn

Respostas:

115

Estou escrevendo esta resposta porque OP enfatizou que:

o que eu estou interessado é porque *.*combina todos os arquivos, como indicado na pergunta

O DIRcomando vem de uma hora em que:

  1. Período (.) Não foi permitido como um caractere em nomes de arquivos ou pastas
  2. Os nomes de arquivos e pastas eram restritos a 8 caracteres para nome e 3 caracteres para extensões

Portanto, por esse padrão, *.*significava qualquer nome e qualquer extensão . Não significa uma string contendo um ".", Que pode ou não ter caracteres antes ou depois do "." .

A política da Microsoft está preservando a compatibilidade com versões anteriores. Portanto, essa interpretação de *.*é retida.

Mas no Windows PowerShell, *.*significa uma string contendo um ".", Que pode ou não ter caracteres antes ou depois do "." .

jpaugh
fonte
25
O sistema de arquivos original nem armazenou o próprio período no disco, apenas os 11 caracteres que compunham o resto do nome.
Sr. Lister
7
Vale a pena notar que arquivos e pastas sem extensões ainda são tratados como tendo uma extensão em branco . Portanto, uma pasta chamada " Folder." e uma pasta chamada " Folder" são nomeadas da mesma forma, no que diz respeito às janelas.
BrainSlugs83
2
@MrLister Interessante. Como o antigo FS armazenava nomes de arquivos AA.BBcom <8 na primeira parte e <3 na extensão? Será que apenas preenchia com espaços?
Kelvin
3
@ Kelvin, sim, as duas partes foram separadamente espaçadas.
plugwash
12

Por que é que?

Pode-se encontrar uma resposta para " Por que isso? " No artigo Wildcards :

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)

Regras de correspondência curinga

  • *Geralmente corresponde a 0 ou mais caracteres, com uma exceção (consulte a próxima regra). O curinga não-guloso é livre para corresponder a tantos ou quantos caracteres forem necessários para que o restante da máscara corresponda.

  • *.No final da máscara, corresponde a 0 ou mais caracteres, exceto {dot}. Na verdade, a regra se aplica a qualquer número de {dot} e {space} caracteres entre o * e o terminal {dot}. A expressão regular para este termo é"[*][. ]*[.]$"

  • ?Corresponde 0 ou um caractere, exceto {dot}. A única vez que corresponde a 0 caracteres é quando corresponde ao final do nome ou à posição antes de {dot}. O ponto de interrogação também pode ser usado mais de uma vez para corresponder a mais de um caractere.

Implicação . O último {dot} em um nome de arquivo / pasta separa o nome base e a extensão. assim

  • dir *.exibe todos os itens sem extensão e
  • dir *.*exibe todos os itens com extensão de zero ou mais caracteres .

Estritamente falando, dir *.exibe todos os itens sem período ( .) no nome . (BTW, Naming Files, Paths e Namespaces MSDN artigo diz explicitamente que " é aceitável especificar um período como o primeiro caractere de um nome ".)

Existe alguma maneira de listar apenas arquivos com um ponto?

Acho que não. No entanto, há uma solução alternativa com uma expressão regular apropriada.

PowerShell (solução de escopo total, se usada em um 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 (apenas uma ideia, pode exigir alguma elaboração):

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

Adendo: um bônus e explicação

Um palpite intuitivo que Nameé concatenado BaseNamee Extension não é válido . O script a seguir prova sua utilização cmde os PowerShellprincipais recursos, e o regex estranho ^..*\...*$ é derivado de seus 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}"

Saída :

==> 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 a definição de BaseNamepropriedade, diferente para arquivos e pastas:

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

Minha resposta original foi baseada em mal-entendidos imperdoáveis:

Leia 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

Outra abordagem: aplicar findstrregex comodir *.* | findstr /V "<.*>"

JosefZ
fonte
o que eu estou interessado é porque *.*combina todos os arquivos , como indicado na pergunta
phuclv
Temo sua sugestão alternativa (findstr) não encontrar pastas que começam com um .como .dbus-keyrings, .VirtualBoxe .vscode.
22
Então, dir /A:-Dlista apenas arquivos que são felizes?
Quentin
4
"Existe alguma maneira de listar apenas arquivos com um ponto?" dir /A:-Destá incorreto. 1 / lista os arquivos sem extensão. 2 / ele não lista os diretórios que têm um .em seu nome (perfeitamente legal)
DavidPostill
3
omg ... tem sido décadas desde a última vez que vi "@echo off"
rupps
6

Existe alguma maneira de listar apenas arquivos com um ponto?

Você pode corresponder nomes de arquivos com um ponto usando o caractere curinga não documentado <, que corresponde a uma sequência de 0 ou mais caracteres no nome da base ou a uma sequência de 0 ou mais caracteres na extensão:

dir "<.<"

Lembre-se de que <também é um meta-caractere, portanto, é necessário citar ou escapar sempre que for usado em um padrão a partir do shell de comando.

feersum
fonte
excelente. Este curinga não documentado existe
phuclv
1

O interpretador de linha de comando verá " . " Como "todos os nomes de arquivo base" com "todas as extensões". Uma extensão em branco ainda é uma extensão , portanto, será correspondida e retornada com a lista. Como outros explicaram, esta é uma ressaca de versões anteriores do Windows e do MS-DOS.

Se você está feliz em procurar usando o PowerShell, encontrar esses arquivos é muito mais fácil. Observe que, no PowerShell, "dir" é um alias para o cmdlet "Get-ChildItem".

Para encontrar todos os arquivos (não diretórios / pastas) que possuam uma extensão (por exemplo, "meuarquivo.txt", mas não "arquivoWithNoExt"):

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

a opção "-af" é uma abreviação de "-File", que restringe os objetos de retorno apenas aos arquivos. "-ad" só obteria diretórios. O "\." significa "um caractere de ponto literal". Sem a barra invertida, o ponto corresponderia a qualquer caractere, como por regex padrão.

Para obter todos os arquivos onde havia um ponto no nome sem a extensão, bem como uma extensão (por exemplo, "myDocument_v1.1.doc" mas não "myfile.txt"):

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

No entanto, observe que isso excluirá um arquivo com o nome, como ".archive", com um ponto precedente. Isso ocorre porque é tratado como não tendo nenhum nome de base e uma extensão de "archive". Se você quiser incluir estes:

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

Aqui, o padrão de correspondência diz "Um ponto literal, OR (|) BeginningOfString (^) seguido por EndOfString ($) (isto é, uma string vazia)". Como um arquivo não pode ter um nome de base e uma extensão vazios , ele encontrará os arquivos que começam com um ponto.

Dave_J
fonte
no PowerShell ls *.*é suficiente, como muitos outros já responderam antes de você
phuclv
-2

Se você digitar o comando acima, então aqui: * (este é um curinga que significa qualquer sequência de caracteres) seguido por um ponto (.) Seguido por * isso pode ser interpretado como mostrar todos os arquivos que possuem nome como (qualquer sequência de caracteres ) (qualquer seqüência de caracteres) que significa ainda que mostra todos os arquivos com qualquer extensão.

Rahul Kant
fonte
1
Então, por que está Program Filesincluído na lista? Não corresponde ao padrão <sequence of characters>.<sequence of characters>.
gronostaj
Pense nisso mais como <Seqüência de zero ou mais caracteres> É por isso que ele também pegaria um arquivo chamado ".info" onde o nome base está em branco.
Dave_J