Dlaczego `dir *. *` Udostępnia mi wszystkie pliki i foldery?

62

Po uruchomieniu dir *.*generuje nieoczekiwane wyniki. Wyświetlane są nawet pliki i foldery bez kropki w nazwie. Na przykład

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

Dlaczego? Czy jest jakiś sposób, aby wyświetlić tylko pliki z kropką?

phuclv
źródło
19
Kropka jest zawsze tam, po prostu nie jest drukowana, chyba że coś za nią podąża. Innymi słowy, możesz pomyśleć, że plik ma nazwę „to mój plik”, ale potajemnie nazwa to „to mój plik”. z niczym po kropce. Analogicznie możesz pomyśleć, że nazwa DNS tej witryny to „superuser.com”, ale tak naprawdę to „superuser.com”. z niczym po drugiej kropce.
Todd Wilcox
12
@ToddWilcox jest poprawny tylko w systemie DOS. Nowoczesne systemy plików w systemie Windows nie mają już oddzielnej przestrzeni nazw rozszerzeń
phuclv
13
@ LưuVĩnhPhúc Podsystem Win32 traktuje nazwy plików, które nie zawierają .takich, jakie mają .na końcu, do wielu celów, w tym do tego.
CodesInChaos
2
Foldery, które nie zawierają .znaku, mają .na końcu znak domyślny . - Możesz mieć folder o nazwie „Blah.old”, na przykład, a wtedy miałby tradycyjne 3-literowe rozszerzenie pliku; codzienne użytkowanie Blahjest jednak takie samo jak „ Blah.”, niezależnie od tego, czy jest to plik, czy folder.
BrainSlugs83
9
@ can-ned_food Todd Wilcox ma rację co do DNS. Główna strefa DNS jest nazywana dosłownie ., a etykiety w nazwach DNS są oddzielone .(dlatego nazwa głównej strefy DNS jest pojedynczą etykietą o zerowej długości). Jedno dziecko podstawowej strefy DNS .jest com., a jedno dziecko com.jest superuser.com.i tak dalej.
CVn

Odpowiedzi:

115

Piszę tę odpowiedź, ponieważ OP podkreśliła, że:

interesuje mnie to, dlaczego *.*pasuje do wszystkich plików, jak podano w pytaniu

DIRPolecenie pochodzi z czasów, gdy:

  1. Kropka (.) Nie była dozwolona jako znak w nazwach plików lub folderów
  2. Nazwy plików i folderów były ograniczone do 8 znaków dla nazwy i 3 znaków dla rozszerzeń

Dlatego przez ten standard *.*rozumie się bez względu na nazwę i rozszerzenie . To nie znaczy łańcuch zawierający „« które mogą lub nie mogą mieć znaki przed lub po».” .

Zasady Microsoft zachowują zgodność wsteczną. Dlatego ta interpretacja *.*zostaje zachowana.

Ale w Windows PowerShell *.*oznacza ciąg zawierający „.”, Który może, ale nie musi zawierać znaków przed lub po „.” .

jpaugh
źródło
25
Oryginalny system plików nawet nie zapisywał samego okresu na dysku, tylko 11 znaków stanowiło resztę nazwy.
Pan Lister
7
Warto zauważyć, że pliki i foldery bez rozszerzeń są nadal traktowane jako posiadające puste rozszerzenie . Dlatego folder o nazwie „ Folder.” i folder o nazwie „ Folder” są nazywane tak samo, jeśli chodzi o system Windows.
BrainSlugs83
2
@MrLister Ciekawe. W jaki sposób stare FS zapisywały nazwy plików, takie jak AA.BB<8 w pierwszej części i <3 w rozszerzeniu? Czy to tylko pad ze spacjami?
Kelvin
3
@ Kelvin tak, dwie części zostały osobno wypełnione spacją.
płyn do płukania
12

Dlaczego?

Odpowiedź na „ Dlaczego to jest? ” Można znaleźć w artykule 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)

Reguły dopasowania symboli wieloznacznych

  • *Zasadniczo dopasowuje dowolne 0 lub więcej znaków, z jednym wyjątkiem (patrz następna reguła). Non-chciwy symbol wieloznaczny może dopasować dowolną liczbę znaków, tak aby dopasować pozostałą część maski.

  • *.Na końcu maski pasuje dowolne 0 lub więcej znaków oprócz {kropki}. W rzeczywistości reguła ma zastosowanie do dowolnej liczby znaków {kropka} i {spacja} między * a terminalem {kropka}. Wyrażenie regularne tego terminu to"[*][. ]*[.]$"

  • ?Dopasuj 0 lub jeden znak, z wyjątkiem {kropki}. Pasuje do 0 znaków tylko raz, gdy pasuje do końca nazwy lub pozycji przed {kropką}. Znaku zapytania można także użyć więcej niż jeden raz, aby dopasować więcej niż jeden znak.

Implikacja . Ostatni {dot} w pliku / nazwy folderu oddziela nazwę bazową i rozszerzenie. Więc

  • dir *.wyświetla wszystkie elementy bez rozszerzenia oraz
  • dir *.*wyświetla wszystkie elementy z rozszerzeniem zera lub więcej znaków .

Ściśle mówiąc, dir *.wyświetla wszystkie elementy bez kropki ( .) w nazwie . (BTW, nazwy plików, ścieżki i przestrzenie nazw Artykuł MSDN wyraźnie stwierdza, że „ dopuszczalne jest określenie kropki jako pierwszego znaku nazwy ”).

Czy jest jakiś sposób, aby wyświetlić tylko pliki z kropką?

Nie wydaje mi się Istnieje jednak obejście z odpowiednim wyrażeniem regularnym.

PowerShell (pełne rozwiązanie, jeśli jest używane w konsoli PowerShell ):

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

Cmd (tylko pomysł, może wymagać dopracowania):

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

Dodatek: premia i wyjaśnienie

Intuicyjne zgadywanie, które Namejest połączone BaseNamei Extension nie ma zastosowania . Poniższy skrypt dowodzi, że używa cmdi PowerShellpodstawowych funkcji, a dziwny ^..*\...*$ regex pochodzi z jego wyników.

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

Wyjście :

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

Porównaj definicję BaseNamewłaściwości, inną dla plików i folderów:

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

Moja pierwotna odpowiedź była oparta na niewybaczalnym nieporozumieniu:

Przeczytaj dir /?, użyj 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

Inne podejście: zastosuj findstrwyrażenie regularne jakodir *.* | findstr /V "<.*>"

JosefZ
źródło
interesuje mnie to, dlaczego *.*pasuje do wszystkich plików , jak stwierdzono w pytaniu
phuclv
Obawiam się, że twoja alternatywna sugestia (findstr) nie znajdzie folderów zaczynających się od .podobnego .dbus-keyrings, .VirtualBoxi .vscode.
22
dir /A:-DWymienia więc tylko pliki, które są szczęśliwe?
Quentin
4
„Czy jest jakiś sposób, aby wyświetlić tylko pliki z kropką?” dir /A:-Djest nieprawidłowe. 1 / wyświetla listę plików bez rozszerzenia. 2 / nie zawiera katalogów, które mają .w swoim imieniu (całkowicie legalne)
DavidPostill
3
omg ... minęło dziesięciolecia, odkąd ostatnio widziałem „@echo off”
rupps
7

Czy jest jakiś sposób, aby wyświetlić tylko pliki z kropką?

Możesz dopasować nazwy plików do kropki, używając nieudokumentowanej symboli wieloznacznej <, która pasuje albo do sekwencji 0 lub więcej znaków w nazwie basename, albo do sekwencji 0 lub więcej znaków w rozszerzeniu:

dir "<.<"

Pamiętaj, że <jest to również metaznak, więc musisz cytować lub uciec z niego, ilekroć użyjesz go we wzorcu z powłoki poleceń.

feersum
źródło
1
doskonały. Ten nieudokumentowany symbol wieloznaczny rzeczywiście istnieje
phuclv
1

Interpreter wiersza poleceń będzie widział „ . ” Jako „Wszystkie podstawowe nazwy plików” z „wszystkimi rozszerzeniami”. Puste rozszerzenie jest nadal rozszerzeniem , więc zostanie dopasowane i zwrócone z listą. Jak wyjaśnili inni, jest to kac z wcześniejszych wersji systemu Windows i MS-DOS.

Jeśli chcesz wyglądać przy użyciu programu PowerShell, znalezienie tych plików jest znacznie łatwiejsze. Zauważ, że w PowerShell „dir” to alias polecenia cmdlet „Get-ChildItem”.

Aby znaleźć wszystkie pliki (nie katalogi / foldery), które mają rozszerzenie (np. „Myfile.txt”, ale nie „FileWithNoExt”):

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

przełącznik „-af” jest skrótem dla „-File”, który ogranicza obiekty zwrotne tylko do plików. „-ad” otrzyma tylko katalogi. „\”. oznacza „dosłowny znak kropki”. Bez ukośnika kropka pasowałaby do dowolnego znaku, zgodnie ze standardowym wyrażeniem regularnym.

Aby pobrać wszystkie pliki z kropką w nazwie bez rozszerzenia, a także z rozszerzeniem (np. „MyDocument_v1.1.doc”, ale nie „myfile.txt”):

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

Należy jednak pamiętać, że spowoduje to wykluczenie pliku o nazwie takiej jak „.archive” z poprzedzającą kropką. Wynika to z faktu, że jest traktowany jako nieposiadający nazwy basename i rozszerzenia „archiwum”. Jeśli chcesz dołączyć te:

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

Tutaj wzór dopasowania mówi „Dosłowna kropka, LUB (|) BeginningOfString (^), a następnie EndOfString ($) (tj. Pusty ciąg znaków)”. Ponieważ plik nie może mieć zarówno pustej nazwy basename, jak i rozszerzenia, znajdzie pliki zaczynające się od kropki.

Dave_J
źródło
ls *.*wystarczy w PowerShell , jak wielu innych przed tobą odpowiedziało
phuclv
-2

Jeśli wpiszesz powyższą komendę, to tutaj: * (jest to symbol wieloznaczny, co oznacza dowolną sekwencję znaków), po której następuje kropka (.), Po której następuje * to może być interpretowane jako pokaż wszystkie pliki o podobnej nazwie (dowolna sekwencja znaków ). (dowolna sekwencja znaków), co dodatkowo oznacza, że ​​pokazują wszystkie pliki z dowolnym rozszerzeniem.

Rahul Kant
źródło
1
Dlaczego zatem znajduje Program Filessię na liście? Nie pasuje do wzoru <sequence of characters>.<sequence of characters>.
gronostaj
Pomyśl o tym bardziej jako <Sekwencja zero lub więcej znaków> To dlatego też wybrałby plik o nazwie „.info”, w którym podstawowa nazwa jest pusta.
Dave_J