Корень этой проблемы - сочетание неправильного использования рекурсии в сочетании с фильтрацией.Я рассмотрю несколько примеров, чтобы проиллюстрировать это.Сначала мы должны установить пример структуры каталогов:
mkdir Temp
mkdir Temp\bin
mkdir Temp\obj
mkdir Temp\node_modules
mkdir Temp\node_modules\bin
mkdir Temp\node_modules\obj
Out-File .\Temp\Readme.md
Out-File .\Temp\bin\Readme.md
Out-File .\Temp\obj\Readme.md
Out-File .\Temp\node_modules\Readme.md
Out-File .\Temp\node_modules\bin\Readme.md
Out-File .\Temp\node_modules\obj\Readme.md
cd .\Temp\
Давайте попробуем несколько примеров.Я передам содержимое Get-ChildItem
в Select-Object
, чтобы лучше проиллюстрировать, что мы получаем.Во-первых, ваниль Get-ChildItem
:
PS C:\Temp> Get-ChildItem | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\node_modules
C:\Temp\obj
C:\Temp\Readme.md
Возвращает то, что мы ожидаем, эквивалентно dir
.Теперь давайте попробуем -Include
только для «включения» папки bin
.
PS C:\Temp> Get-ChildItem -Include bin | Select-Object FullName
PS C:\Temp>
Хммм.Он ничего не возвращал ... Мы думали, что он возьмет список всего и "только" включит папку bin.Вместо этого она интерпретировала команду как Get-ChildItem
из «ничего» (потому что мы не указали файлы для получения) и «Включить» из «ничего», шаблон bin
.Это имеет смысл, и оно перечислено в Docs , что «Включить требует параметр Path».Хорошо.Давайте изменим это, чтобы фактически получить все *
тогда сделать -Include bin
, тогда мы должны получить то, что хотим ... Верно?
PS C:\Temp> Get-ChildItem * -Include bin | Select-Object FullName
PS C:\Temp>
Ху?Я думал с подстановочным знаком, это будет включать в себя папку bin
правильно?Разве это не так? .... ну, не совсем.Давайте изменим его на -Include
файл вместо каталога:
PS C:\Temp> Get-ChildItem * -Include Readme.md | Select-Object FullName
FullName
--------
C:\Temp\Readme.md
Так что это похоже на явную фильтрацию, с подстановочным знаком для файлов , а не каталогов .Тогда как работает оригинальный пример, где мы включили каталоги? ... Ну, это потому, что -Recurse
работает по-другому.-Recurse
изменяет то, что мы получаем, возвращает все , поэтому Include
работает:
PS C:\Temp> Get-ChildItem -Include bin -Recurse | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\node_modules\bin
В этом примере, когда нам не нужно указывать подстановочный знак *
Фильтр -Recurse
неявно получает все из каталога.Обратите внимание: в него включены каталоги, соответствующие названию bin
.Кроме того, обратите внимание, что он не включает файлы внутри каталогов.
Почему пример 1:
gci -include bin,obj -recurse | remove-item -force -recurse
Работает потому, что Get-ChildItem
возвращает каталоги, а Remove-Item
с-Force
и -Recurse
заботятся об удалении файлов.
Чтобы доказать, что ничего лишнего не происходит, давайте сделаем -Exclude node_modules
:
PS C:\Temp> Get-ChildItem -Exclude node_modules -Recurse | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\bin\Readme.md
C:\Temp\node_modules\bin
C:\Temp\node_modules\bin\Readme.md
C:\Temp\node_modules\obj
C:\Temp\node_modules\obj\Readme.md
C:\Temp\node_modules\Readme.md
C:\Temp\obj
C:\Temp\obj\Readme.md
C:\Temp\Readme.md
Ну ... что вернулосьбольше, чем ожидалось ... но нет.Обратите внимание, что он не вернул C:\Temp\node_modules
.Это потому что -Exclude node_modules
было правильно.Он исключил папку с конкретным названием: node_modules
и включил все остальное.
Вот почему не работает второй пример:
gci -exclude node_modules -include bin,obj -recurse | remove-item -force -recurse
Фильтр исключения исключит конкретную папку с именем node_modules
, но из-за -Recurse
будет -Include
любая подпапка, которая соответствует bin
или obj
.Который конечно , node_modules
имеет тонну, и, следовательно, не работает так, как мы хотим.
Итак, если -Include
не работает с каталогами, и -Recurse
заходит слишком глубоко, что решит вопрос @cResults?Что ж, вместо того, чтобы возиться с фильтрами, почему бы нам просто не спросить, какие папки нам нужны, как обычно?
PS C:\Temp> Get-ChildItem bin,obj | Select-Object FullName
FullName
--------
C:\Temp\bin\Readme.md
C:\Temp\obj\Readme.md
Ну, все в порядке, он вернул содержимое из папок, как и в предыдущем примере, дочерние элементы , а не каталоги ... Ну, мы действительно хотели, чтобы был элемент папки , поэтому вместо Get-ChildItem
мы используем Get-Item
:
PS C:\Temp> Get-Item bin,obj | Select-Object FullName
FullName
--------
C:\Temp\bin
C:\Temp\obj
А теперь, с переключателем на Get-Item
мы получаем папку, а не дочерние элементы внутри папки, которые мы теперь можем использовать с Remove-Item
который позаботится обо всем остальном:
Get-Item bin,obj | Remove-Item -Force -Recurse