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

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

Ответы

Ответ 1

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

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

Вместо этого PowerShell использует FsRtlIsNameInExpression -подобный алгоритм для сопоставления шаблонов Filter. Алгоритм основан на старом поведении 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 ошибочно обрабатывает "<> как недопустимые, несимвольные символы. (Это позволяет .*?.) Это способствует пониманию того, что -фильтр является неполным, неустойчивым и ошибочным. Вы можете увидеть реализацию .NET(глючной) алгоритма на 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 дает значительно разные результаты при тестировании этих "gotchas". Протестировано с помощью WINE 1.9.6.

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

Ответ 2

На -filter почти ничего нет.

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

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

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

Get-ChildItem -filter 'test*' -recurse

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

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

Ответ 3

В следить, о чем говорится в 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 коротких имен.

Ответ 4

Они совпадают с документами для всех командлетов. В командной строке введите:

Get-Help Get-ChildItem

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

Get-Help Get-ChildItem -Detailed

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

Get-Help Get-ChildItem -Full

EDIT: Пока -Detail отлично работает, поскольку PS автоматически устраняет неоднозначность имен параметров, никогда не мешает им правильно:)