Powershell, поставщик файловой системы, фильтрация Get-ChildItem ... где находятся официальные документы? - PullRequest
14 голосов
/ 08 июля 2011

Как упоминалось в другом вопросе , если вы пытаетесь выполнить команду Get-ChildItem -filter ..., вы более ограничены, чем если бы вы использовали -include вместо -filter.Я хотел бы прочитать официальные документы по синтаксису фильтрации провайдера файловой системы, но после получаса поиска я все еще не нашел их.Кто-нибудь знает, где искать?

Ответы [ 4 ]

17 голосов
/ 19 июля 2013

tl; dr -Filter использует реализацию .NET FsRtllsNameInExpression, которая документирована в MSDN вместе с базовой информацией о сопоставлении с образцом. Алгоритм не является интуитивно понятным по причинам совместимости, и вам, вероятно, следует избегать использования этой функции. Кроме того, .NET имеет множество ошибок в своей реализации.

-Filter не использует систему фильтрации, предоставляемую PowerShell, то есть не использует систему фильтрации, описанную Get-Help about_Wildcard. Скорее, он передает фильтр в Windows API. Поэтому фильтрация работает так же, как и в любой другой программе, использующей Windows API, например cmd.exe.

Вместо этого PowerShell использует FsRtlIsNameInExpression -подобный алгоритм для сопоставления с образцом фильтра. Алгоритм основан на старом поведении MS-DOS, поэтому он пронизан предостережениями, которые сохраняются для устаревших целей. Обычно говорят, что он имеет три общих специальных символа. Точное поведение является сложным, но оно более или менее похоже на следующее:

  • *: соответствует любому количеству символов (включая ноль)
  • ?: соответствует ровно одному символу, исключая последний период в имени
  • .: если последний период в шаблоне, привязывается к последнему периоду в имени файла или к концу имени файла, если у него нет периода; также может соответствовать буквальному периоду

Просто, чтобы сделать вещи более сложными, Windows добавила три дополнительных специальных символа, которые ведут себя точно так же, как старые специальные символы MS-DOS. Оригинальные специальные символы теперь ведут себя немного иначе, чтобы учитывать более гибкие файловые системы.

  • " эквивалентно MS-DOS . (DOS_DOT и ANSI_DOS_DOT в ntifs.h)
  • < эквивалентно MS-DOS ? (DOS_QM и ANSI_DOS_QM в ntifs.h)
  • > эквивалентно MS-DOS * (DOS_STAR и ANSI_DOS_STAR в ntifs.h)

Многие источники, похоже, обращают < и >. Страшно, но Microsoft путает их в их реализации .NET , что означает, что они также обращены вспять в PowerShell. Кроме того, все три подстановочных знака совместимости недопустимы с -Filter, так как System.IO.Path ошибочно рассматривает "<> как недопустимые, не подстановочные символы . (Это позволяет .*?.) Это способствует пониманию того, что -Filter является неполным, нестабильным и глючным. Вы можете увидеть реализацию (. Глючного) .NET (10) * на GitHub .

Это дополнительно усложняется тем, что алгоритм поддерживает 8.3 совместимых имен файлов , иначе называемых «короткими» именами файлов. (Вы, вероятно, видели их раньше; они выглядят примерно так: SOMETH~1.TXT) Файл соответствует шаблону, если его полное имя файла или соответствует его короткому имени файла. FrankFranchise имеет больше информации об этом предупреждении в своем ответе.

В ранее опубликованной статье MSDN по FsRtlIsNameInExpression содержится самая последняя документация по сопоставлению шаблонов имен файлов Windows, но она не слишком многословна. Для более подробного объяснения того, как сопоставление использовалось в MS-DOS и как это влияет на современное сопоставление, эта статья в блоге MSDN - лучший источник, который я нашел. Вот основная идея:

  • Каждое имя файла было ровно 11 байтов.
    • Первые 8 байтов хранят тело имени файла, дополненное пробелами справа
    • Последние 3 байта хранят расширение, дополненное справа пробелами
  • Письма были преобразованы в верхний регистр
  • Буквы, цифры, пробелы и некоторые символы соответствуют только себе
  • ? соответствует любому отдельному символу, кроме пробелов в расширении
  • . заполнит оставшиеся первые 8 байтов пробелами, а затем перейдет к 9-му байту (начало расширения)
  • * заполнит оставшуюся часть текущего раздела (текст или расширение) вопросительными знаками, а затем перейдет к следующему разделу (или концу шаблона)

Преобразования будут выглядеть так:

                          11
User             12345678901
------------     -----------
ABC.TXT       >  ABC     TXT
WILDCARD.TXT  >  WILDCARDTXT
ABC.???       >  ABC     ???
*.*           >  ???????????
*.            >  ????????   
ABC.          >  ABC        

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

Name                 Compat Name
-----------------------------------------------
Apple1.txt           APPLE1  .TXT
Banana               BANANA  .
Something.txt        SOMETH~1.TXT
SomethingElse.txt    SOMETH~2.TXT
TXT.exe              TXT     .EXE
TXT.eexe             TXT~1   .EEX
Wildcard.txt         WILDCARD.TXT

Я провел небольшое тестирование этих подстановочных знаков в Windows 10 и получил очень противоречивые результаты, особенно DOS_DOT ("). Если вы тестируете их самостоятельно из командной строки, вам, вероятно, потребуется их экранировать (например, dir ^>^"^> в cmd.exe для эмуляции MS-DOS *.*).

*.*                 (everything)
<"<                 (everything)
*                   (everything)
<                   Banana
.                   (everything)
"                   (everything)
*.                  Banana
<"                  Banana
*g.txt              Something.txt
<g.txt              Something.txt
<g"txt              (nothing)
*1.txt              Apple1.txt, Something.txt
<1.txt              Apple1.txt, Something.txt
<1"txt              (nothing)
*xe                 TXT.eexe, TXT.exe
<xe                 (nothing)
*exe                TXT.eexe, TXT.exe
<exe                TXT.exe
??????.???          Apple1.txt, Asdf.tx, Banana, TXT.eexe, TXT.exe
>>>>>>.>>>          Apple1.txt, Asdf.tx, TXT.eexe, TXT.exe
>>>>>>">>>          Banana
????????.???        (everything)
>>>>>>>>.>>>        (everything except Banana)
>>>>>>>>">>>        Banana
???????????.???     (everything)
>>>>>>>>>>>.>>>     (everything except Banana)
>>>>>>>>>>>">>>     Banana
??????              Banana
>>>>>>              Banana
???????????         Banana
>>>>>>>>>>>         Banana
????????????        Banana
????                (nothing)
>>>>                (nothing)
Banana??.           Banana
Banana>>.           Banana
Banana>>"           Banana
Banana????.         Banana
Banana>>>>.         Banana
Banana>>>>"         Banana
Banana.             Banana
Banana"             Banana
*txt                Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt
<txt                Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt
*t                  Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt
<t                  (nothing)
*txt*               Apple1.txt, Something.txt, SomethingElse.txt, TXT.eexe, TXT.exe, Wildcard.txt
<txt<               Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt
*txt<               Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt
<txt*               Apple1.txt, Something.txt, SomethingElse.txt, TXT.eexe, TXT.exe, Wildcard.txt

Примечание. На момент написания статьи алгоритм сопоставления WINE дает значительно отличающиеся результаты при тестировании этих "ошибок". Протестировано с WINE 1.9.6.

Как видите, обратно совместимые подстановочные знаки MS-DOS неясны и содержат ошибки. Даже Microsoft реализовала их неправильно хотя бы один раз , и неясно, является ли их текущее поведение в Windows преднамеренным. Поведение " кажется совершенно случайным, и я ожидал, что результаты двух последних тестов поменяются местами.

8 голосов
/ 08 июля 2011

На -filter.

почти ничего нет.

Есть немного, когда вы делаете Get-Help Get-ChildItem -full, но я уверен, что вы видели это . Также в блоге Powershell есть пост . Ни один не приводит примеры.

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

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

Get-ChildItem -filter 'test*' -recurse

Это отфильтровывает все результаты в текущем каталоге, прежде чем возвращать что-либо для рекурсии. Если бы у меня был каталог, который начинался с «test», он бы использовал этот каталог (поскольку провайдер вернул бы его в командлет), но никаких других.

Как показывает пример, он может обращаться к свойствам некоторых провайдеров. В провайдере FileSystem вы можете использовать только строки подстановочных знаков, совпадающие с именем каталога или файла (лист, не полностью).

3 голосов
/ 22 марта 2016

До , следуйте на том, что упомянуто Zenexer , вы должны увидеть о тех же результатов, которые вы увидите, используя те же фильтры с cmd.exe.Это включает в себя вещи, которые вы, возможно, не ожидаете, такие как 8.3 короткие имена файлов .Вы можете проверить это сами.

Создайте несколько файлов примеров с помощью PowerShell
md filtertest | cd
(1..1000) | % { New-item -Name ("aaaaa{0:D6}.txt" -f $_) -ItemType File }
Теперь откройте приглашение cmd и выполните
dir /x
dir aaab*

Первая команда показывает короткие имена 8.3.Второй соответствует некоторым файлам, даже если ни в одном из обычных имен нет символа «b», потому что эти файлы содержат «b» в коротком имени.

Теперь вы можете вернуться к PowerShell и запустить ls -Filter aaab*, чтобы снова увидеть те же файлы.Строка -Filter передается в WinAPI, который сопоставляется с этими файлами с 'b' в коротких именах 8.3, точно так же, как dir в cmd.exe.Поэтому при использовании -Filter остерегайтесь непредвиденных результатов, возможно, вы совпадаете с коротким именем 8.3.

Все это предполагает, что на вашем компьютере включены короткие имена 8.3.

0 голосов
/ 08 июля 2011

Это то же место, что и документы для всех командлетов.В командной строке введите:

Get-Help Get-ChildItem

Если этого недостаточно, то:

Get-Help Get-ChildItem -Detailed

Или, если вы действительно хотите копать, тогда:

Get-Help Get-ChildItem -Full

РЕДАКТИРОВАТЬ: Хотя -Detail работает нормально, так как PS автоматически устраняет неоднозначность имен параметров, это никогда не помешает иметь правильное значение:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...