Как предотвратить рекурсию через node_modules для скрипта gci - PullRequest
1 голос
/ 14 мая 2019

Я нашел этот фантастический сценарий PowerShell

gci -include bin,obj -recurse | remove-item -force -recurse

в комментарии Крис J на этот ответ

Я использую это несколько разв день.

Как предотвратить запуск через любые папки node_modules, если они существуют или их дочерние элементы?

Я пробовал различные версии

gci -exclude node_modules -include bin,obj -recurse | remove-item -force -recurse

безуспех.

ОБНОВЛЕНИЕ: Прочитав информативный ответ @ HAL9256, я понял, что не смог включить важное требование.Я запускаю этот скрипт в корне моего git-репо.Поэтому он пересекает несколько папок проекта C #, удаляя папки bin и obj для всех из них.Это необходимо только потому, что очистка решения Visual Studio 2017 и 2019 не удаляет все, и, поскольку мы находимся в процессе преобразования из каркаса в стандарт / ядро, в папке bin и / или obj после очистки остаются артефакты, которые приводят кперерыв при переходе (возможно, из ядра обратно в фреймворк) данного проекта через изменение ветки git.

1 Ответ

0 голосов
/ 14 мая 2019

Корень этой проблемы - сочетание неправильного использования рекурсии в сочетании с фильтрацией.Я рассмотрю несколько примеров, чтобы проиллюстрировать это.Сначала мы должны установить пример структуры каталогов:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...