Путаница с параметром -Include командлета Get-ChildItem

Из документации:

-Включают

Извлекает только указанные элементы. Значение этого параметра определяет параметр Path. Введите элемент пути или шаблон, например «* .txt». Подстановочные знаки разрешены.

Параметр Include действует только в том случае, если команда включает параметр Recurse или путь ведет к содержимому каталога, например C: \ Windows *, где подстановочный знак указывает содержимое каталога C: \ Windows.

Мое первое понимание было:

c:\test\a.txt
c:\test\b.txt

Итак, чтобы получить 'a.txt' и 'b.txt', я могу написать:

gci -Path "c:\test\*" -Include "*.txt"

И это работает. Но теперь рассмотрим такую ​​иерархию:

c:\test\a.txt
c:\test\b.txt
c:\test\c.txt\c.txt

Эта же команда возвращает: a.txt, b.txt, c.txt

Фактическая логика выглядит так:

-Include используется для сопоставления всех сущностей, указанных в -Path. Если совпавший элемент является файлом - верните его. Если совпавший элемент - это папка, загляните внутрь и верните соответствующие дочерние элементы первого уровня.

Также в документации говорится:

Параметр Include действует только в том случае, если команда включает параметр Recurse или путь ведет к содержимому каталога ...

Это тоже неправильно. Например.

gci -Path "c:\test" -Include "*.txt"

Он ничего не возвращает, а без -Include я получаю содержимое папки. Итак, -Include определенно "эффективен". Что на самом деле здесь происходит? -Path указывает "c: \ test", а -Include пытается сопоставить этот путь. Поскольку "* .txt" не соответствует "test", ничего не возвращается. Но посмотрите на это:

gci -Path "c:\test" -Include "*t"

Он возвращает a.txt, b.txt и c.txt как «* t» сопоставленный «тест» и сопоставленный со всеми дочерними элементами.

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


person alex2k8    schedule 26.04.2009    source источник


Ответы (6)


Вы сбиваете с толку использование -include. Флаг -include применяется к пути, а не к его содержимому. Без использования рекурсивного флага единственный рассматриваемый путь - это указанный вами путь. Вот почему последний приведенный вами пример работает, путь c:\test имеет t в пути и, следовательно, соответствует "*t".

Вы можете проверить это, попробовав следующее

gci -path "c:\test" -in *e*

Это по-прежнему будет производить всех дочерних элементов в каталоге, но не будет соответствовать ни одному из их имен.

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

person JaredPar    schedule 26.04.2009
comment
Я использую PowerShell-v2.0-CTP3, и ваш пример дает пустой набор. - person alex2k8; 26.04.2009
comment
@ alex2k8, не знаю, что тут сказать. Я пробовал этот пример на сборке 1.0 и более поздней версии 2.0, обе дают одинаковые результаты. - person JaredPar; 26.04.2009
comment
@ Джаред, это странно. Пожалуйста, не могли бы вы попробовать gci -path c: * -in *. Я вижу дочерние папки c: \ и все его подпапки на один уровень ниже. Вот аналогичное описание eggheadcafe.com/software/aspnet/32624832 / - person alex2k8; 27.04.2009

Попробуйте параметр -filter (он поддерживает только одно расширение):

dir -filter * .txt

person Shay Levy    schedule 26.04.2009
comment
Фильтр немного отличается, потому что это реализация для конкретного поставщика. Обычно это более эффективно, потому что происходит до того, как данные будут возвращены. Но у него есть своя реализация для каждого поставщика накопителя в PowerShell. Следовательно, в алгоритме сопоставления могут быть небольшие различия. - person JaredPar; 26.04.2009
comment
Я согласен, хотя в данном случае мы говорим о провайдере файловой системы. Спасибо за комментарий. - person Shay Levy; 27.04.2009

Переходя к ответу JaredPar, чтобы выполнить сопоставление с образцом с помощью Get-ChildItem, вы можете использовать общие подстановочные знаки оболочки.

Например:

get-childitem "c:\test\t?st.txt"

где "?" подстановочный знак, соответствующий любому одному символу или

get-childitem "c:\test\*.txt"

который будет соответствовать любому имени файла, заканчивающемуся на ".txt".

Это должно дать вам "более простое" поведение, которое вы искали.

person Steven Murawski    schedule 26.04.2009
comment
Проблема не в том, что вы можете получить только одно расширение? -Include - это строка [], допускающая несколько вариантов соответствия. Спасибо Бен - person Bennett Dill; 03.09.2009

Я только что задал аналогичный вопрос и получил три быстрых ответа о Get-Help для Get-ChildItem.

Ответ находится в полном описании команды (Get-Help Get-ChildItem -full):

The Include parameter is effective only when the command includes the

Параметр Recurse или путь ведет к содержимому каталога, например C: \ Windows *, где подстановочный знак указывает содержимое каталога C: \ Windows.

Таким образом, следующее будет работать без рекурсии.

PS C: \ foo> Get-childitem -path "c: \ foo *" -Include * .txt

Из вопроса о переполнении стека сценариев PowerShell - Get-ChildItem.

Надеюсь, это поможет :-)

person Bennett Dill    schedule 02.09.2009
comment
Бен, на самом деле мой вопрос был немного другим. Обратите внимание, что ваш пример будет возвращать файлы .txt из папки foo, НО он также может неожиданно возвращать файлы и даже папки, например, из каталога c: \ foo \ dir.txt. Попробуйте такую ​​иерархию: c: \ foo \ dir.txt \ file.txt и c: \ foo \ dir.txt \ dir2.txt \ file2.txt. Вы получите: file.txt и dir2.txt! - person alex2k8; 03.09.2009

Включение \* в конце пути должно решить проблему.

PS C:\logfiles> Get-ChildItem .\* -include *.log

Это должно вернуть файлы .log из текущего рабочего каталога (C:\logfiles)

Приведенный выше пример Алекса показывает, что также будет возвращен каталог с именем foo.log. Когда я попробовал, это не так, но прошло 6 лет, и это могло быть связано с обновлениями PS.

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

PS C:\logfiles> Get-Childitem .\* -include *.log | where-object {$_.mode -notmatch "d"}

Это должно исключить что-либо с установленным режимом «каталог».

person Stephquan    schedule 08.04.2015
comment
Включение * в конце пути не всегда работает. Я не знаю, как указать значение -Include для сопоставления файлов без расширения имени файла. Указание * в качестве шаблона -Include будет соответствовать таким файлам, но заставляет Get-ChildItem действовать рекурсивно. Если бы -Include вел себя так же, как Exclude, это было бы легко. - person MikeOnline; 05.08.2015

get-childitem -include работает только с -recursive или подстановочным знаком в пути. Я считаю это ошибкой [думал, что в PS 6 все было по-другому].

person js2010    schedule 16.06.2018
comment
Это не так, еще нужно добавить \*, чтобы он заработал. - person UNeverNo; 18.07.2019