Почему `dir *.*` Дает мне все файлы и папки?
Когда я бегу 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
Это почему? Есть ли способ перечислить только файлы с точкой?
5 ответов
Я пишу этот ответ, потому что OP подчеркнул, что:
что меня интересует, почему
*.*
соответствует всем файлам, как указано в вопросе
DIR
Команда приходит со времени, когда:
- Точка (.) Не допускается в качестве символа в именах файлов или папок
- Имена файлов и папок были ограничены 8 символами для имени и 3 символами для расширений
Следовательно, по этому стандарту, *.*
имел в виду любое имя и любое расширение. Это не означает строку, содержащую ".", Которая может содержать или не содержать символы до или после ".",
Политика Microsoft сохраняет обратную совместимость. Следовательно, это толкование *.*
сохраняется.
Но в Windows PowerShell, *.*
означает строку, содержащую ".", которая может содержать или не содержать символы до или после ".",
Это почему?
Ответ на вопрос " Почему это так? " Можно найти в статье 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 "<.*>"
Есть ли способ перечислить только файлы с точкой?
Вы можете сопоставлять имена файлов с точкой, используя недокументированный подстановочный знак <
, которая соответствует либо последовательности из 0 или более символов в базовом имени, либо последовательности из 0 или более символов в расширении:
dir "<.<"
Помни что <
также является метасимволом, поэтому вы должны заключать его в кавычки или экранировать всякий раз, когда используете его в шаблоне из командной оболочки.
Интерпретатор командной строки увидит "." Как "Все базовые имена файлов" со "всеми расширениями". Пустое расширение все еще является расширением, поэтому будет сопоставлено и возвращено со списком. Как объяснили другие, это похмелье от более ранних версий 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($) (т.е. пустая строка)". Поскольку файл не может иметь как пустое базовое имя, так и расширение, он найдет файлы, начинающиеся с точки.
Если вы введете указанную выше команду, то здесь: * (это подстановочный знак, означающий любую последовательность символов), за которым следует точка (.), За которой следует *. Это можно интерпретировать как показ всех файлов с именами, такими как (любая последовательность символов)). (любая последовательность символов), что дополнительно означает, что отображаются все файлы с любым расширением.