Почему `dir *. *` Дает мне все файлы и папки?

62

Когда я бегу, dir *.*это дает неожиданные результаты. Даже файлы и папки без какой-либо точки в их именах перечислены. Например

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

Почему это? Есть ли способ перечислить только файлы с точкой?

phuclv
источник
19
Точка всегда есть, она просто не печатается, если за ней что-то не идет. Другими словами, вы можете подумать, что файл называется «это мой файл», но в тайне он называется «это мой файл». ни с чем после точки. Аналогично, вы можете подумать, что DNS-имя для этого сайта - «superuser.com», но на самом деле это «superuser.com». ни с чем после второй точки.
Тодд Уилкокс
12
@ToddWilcox это правильно только в DOS. Современные файловые системы в Windows больше не имеют отдельного пространства имен расширений
phuclv
13
@ LưuVĩnhPhúc Подсистема Win32 обрабатывает имена файлов, .которые .в конце не содержат слов, которые они имеют, для многих целей, включая эту.
CodesInChaos
2
Папки, которые не содержат .символ, имеют .в конце подразумеваемый символ. - Например, у вас может быть папка с именем «Blah.old», и тогда у нее будет традиционное трехбуквенное расширение файла; для повседневного использования, хотя « Blah» - это то же самое, что и « Blah.», будь то файл или папка.
BrainSlugs83
9
@ can-ned_food Тодд Уилкокс прав насчет DNS. Корневая DNS-зона называется буквально ., а метки в DNS-именах разделены .(таким образом, имя корневой DNS-зоны представляет собой одну метку нулевой длины). Один дочерний элемент корневой DNS-зоны .есть com., а один дочерний com.- superuser.com.и т. Д.
CVn

Ответы:

115

Я пишу этот ответ, потому что OP подчеркнул, что:

меня интересует то, почему *.*совпадает со всеми файлами, как указано в вопросе

Команда DIRприходит со времени, когда:

  1. Точка (.) Не допускается в качестве символа в именах файлов или папок
  2. Имена файлов и папок были ограничены 8 символами для имени и 3 символами для расширений

Поэтому под этим стандартом *.*подразумевается любое имя и любое расширение . Это не означает строку, содержащую «.», Которая может содержать или не содержать символы до или после «.» ,

Политика Microsoft сохраняет обратную совместимость. Следовательно, это толкование *.*сохраняется.

Но в Windows PowerShell *.*означает строку, содержащую «.», Которая может содержать или не содержать символы до или после «.» ,

jpaugh
источник
10
Дополнительное чтение: blogs.msdn.microsoft.com/oldnewthing/20071217-00/?p=24143
grawity
25
Оригинальная файловая система даже не сохраняла сам период на диске, только 11 символов составляют остальную часть имени.
Мистер Листер
7
Стоит отметить, что файлы и папки без расширений по-прежнему считаются пустыми расширениями . Поэтому папка с именем " Folder." и папка с именем " Folder" имеют одно и то же имя в отношении окон.
BrainSlugs83
2
@MrLister Интересно. Как старые файлы FS хранили имена файлов, например, AA.BBс <8 в первой части и <3 в расширении? Это просто с пробелами?
Кельвин
3
@ Кельвин, да, две части были разделены пробелами.
plugwash
12

Почему это?

Ответ на вопрос « Почему это так? » Можно найти в статье 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)

...

Правила подстановочных знаков

  • *Обычно соответствует любому 0 или более символам, за одним исключением (см. Следующее правило). Нежадный подстановочный знак может сопоставлять столько символов, сколько необходимо для соответствия оставшейся части маски.

  • *.В конце маски совпадает любой 0 или более символов, кроме {точка}. В действительности, правило применяется с любым количеством символов {точка} и {пробел} между * и терминалом {точка}. Регулярное выражение для этого термина"[*][. ]*[.]$"

  • ?Совпадение 0 или один символ, кроме {точка}. Единственный раз, когда он соответствует 0 символам, это когда он соответствует концу имени или позиции перед {точкой}. Знак вопроса может также использоваться более одного раза, чтобы соответствовать более чем одному символу.

Смысл . Последний {точка} в имени файла / папки отделяет базовое имя и расширение. Так

  • dir *.отображает все элементы без расширения и
  • dir *.*отображает все элементы с расширением от нуля или более символов .

Строго говоря, dir *.отображает все элементы без точки ( .) в имени . (Кстати, в статье MSDN , названии файлов, путей и пространств имен явно сказано, что « допустимо указывать точку в качестве первого символа имени ».)

Есть ли способ перечислить только файлы с точкой?

Я так не думаю. Однако есть обходной путь с подходящим регулярным выражением.

PowerShell (полное решение, если оно используется в консоли Powershell):

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

Cmd (только идея, может потребовать некоторой проработки):

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

Приложение: бонус и объяснение

Интуитивное предположение, Nameкоторое объединено BaseNameи Extension не имеет места . Следующий скрипт доказывает его использование cmdи PowerShellосновные функции, и странное ^..*\...*$ регулярное выражение выводится из его результатов.

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

Выход :

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

Сравните определение BaseNameсвойства, различного для файлов и папок:

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

Мой первоначальный ответ был основан на непростительном недоразумении:

Читать dir /?, использовать 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

Другой подход: применить findstrрегулярное выражение какdir *.* | findstr /V "<.*>"

JosefZ
источник
меня интересует то, почему *.*совпадает со всеми файлами , как указано в вопросе
phuclv
Боюсь, ваше альтернативное предложение (findstr) не находит папки, начинающиеся с .лайка .dbus-keyrings, .VirtualBoxи .vscode.
22
Так что dir /A:-Dперечисляет только файлы, которые счастливы?
Квентин,
4
"Есть ли способ перечислить только файлы с точкой?" dir /A:-Dэто неверно. 1 / в нем перечислены файлы без расширения. 2 / в нем нет каталогов, в которых есть .имена (совершенно законные)
DavidPostill
3
о боже мой ... прошло уже десятилетия с тех пор, как я последний раз видел "@echo off"
rupps
7

Есть ли способ перечислить только файлы с точкой?

Вы можете сопоставлять имена файлов с точкой, используя недокументированный подстановочный знак <, который соответствует либо последовательности из 0 или более символов в базовом имени, либо последовательности из 0 или более символов в расширении:

dir "<.<"

Помните, что <это также метасимвол, поэтому вы должны заключать его в кавычки или экранировать всякий раз, когда используете его в шаблоне из командной оболочки.

feersum
источник
1
отлично. Этот недокументированный шаблон действительно существует
phuclv
1

Интерпретатор командной строки увидит « . » Как «Все базовые имена файлов» со «всеми расширениями». Пустое расширение все еще является расширением , поэтому будет сопоставлено и возвращено со списком. Как объяснили другие, это похмелье от более ранних версий Windows и MS-DOS.

Если вы счастливы смотреть с помощью PowerShell, найти эти файлы намного проще. Обратите внимание, что в PowerShell «dir» является псевдонимом командлета «Get-ChildItem».

Чтобы найти все файлы (не каталоги / папки), которые имеют расширение (например, «myfile.txt», но не «FileWithNoExt»):

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

ключ "-af" является сокращением для "-File", который ограничивает возвращаемые объекты только файлами. «-ad» получит только каталоги. "\" означает «буквальный символ точки». Без обратной косой черты точка будет соответствовать любому символу в соответствии со стандартным регулярным выражением.

Чтобы получить все файлы, в имени которых была точка, без расширения, а также с расширением (например, «myDocument_v1.1.doc», но не «myfile.txt»):

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

Однако обратите внимание, что это исключит файл с именем, например «.archive», с предыдущей точкой. Это потому, что он рассматривается как не имеющий базового имени и расширения «архив». Если вы хотите включить это:

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

Здесь шаблон совпадения говорит: «Буквальная точка, OR (|) BeginningOfString (^), за которой следует EndOfString ($) (т.е. пустая строка)». Поскольку файл не может иметь как пустое базовое имя, так и расширение, он найдет файлы, начинающиеся с точки.

Dave_J
источник
в PowerShell просто ls *.*достаточно, как многие другие ответили перед вами
phuclv
-2

Если вы введете указанную выше команду, то здесь: * (это подстановочный знак, означающий любую последовательность символов), за которым следует точка (.), За которой следует *. Это можно интерпретировать как показ всех файлов с именами, такими как (любая последовательность символов) ). (любая последовательность символов), что дополнительно означает, что отображаются все файлы с любым расширением.

Рахул Кант
источник
1
Тогда почему Program Filesвключен в список? Это не соответствует шаблону <sequence of characters>.<sequence of characters>.
Гроностай
Думайте об этом больше как о «Последовательности от нуля или более символов». Поэтому он также выберет файл с именем «.info», в котором базовое имя будет пустым.
Dave_J