Если вы работаете с PowerShell, особенно при поиске файлов, наверняка сталкивались с ситуациями, когда команда Get-ChildItem (или её алиас gci) ведёт себя не так, как ожидалось. Например, вы ищете все JAR-файлы, начинающиеся на букву «b», но вместо трёх результатов получаете только один. Давайте разберёмся, почему так происходит и как это исправить.
Как работает фильтрация в Get-ChildItem
Когда вы используете gci с параметрами -Filter и -Recurse, важно понимать, что PowerShell обрабатывает пути и фильтры особым образом. Вот ключевые моменты:
1. Фильтр применяется к имени файла, а не к полному пути. Например, -Filter b*.jar ищет файлы, чьи имена начинаются с «b» и имеют расширение .jar.
2. Wildcards в пути влияют на то, какие папки будут сканироваться. Например, C:toolsbriss* означает: «Ищи в папке C:tools все подпапки, начинающиеся с briss, а потом применяй фильтр к файлам внутри них».
Но иногда это приводит к неочевидным результатам. Представьте структуру папок:
C:toolsBriss-2.0
├─ lib/
│ ├─ bcmail-jdk15-1.46.jar
│ ├─ bcprov-jdk15-1.46.jar
│ ├─ Briss-2.0.jar
Если выполнить команду:
gci C:toolsbriss* -Filter b*.jar -Recurse | Select FullName
Результат будет только один файл- Briss-2.0.jar. Почему?
Оказывается, PowerShell (и старые версии cmd) иногда делят путь на части, если в нём есть wildcards. Например:
C:toolsbriss-2.0.jar интерпретируется как:
– Диск: `C:`
– Путь: `tools`
– Имя файла: `briss-2.0.jar`
Даже если файла briss-2.0.jar нет в C:tools, команда gci начнёт рекурсивный поиск в C:tools, а потом применит фильтр к найденным файлам. В итоге вы получите все файлы с именем briss-2.0.jar в подпапках (например, в C:toolsBriss-2.0lib).
Но почему тогда в некоторых случаях это не работает? Всё дело в специфике wildcards в путях. Если вы напишете:
gci C:toolsbr* -Filter b*.jar -Recurse
PowerShell попытается найти папки, начинающиеся на `br` внутри `C:tools`, а затем применить фильтр. Если таких папок нет (или в них нет подходящих файлов), результат будет пустым. Но в примере выше папка `Briss-2.0` начинается с заглавной буквы, а wildcard br* в PowerShell (в отличие, скажем, от Linux) регистрозависим. Это частая ошибка (кстати, если вы работали с Linux, это может сбить с толку).
Как избежать проблем
1. Используйте точные пути или кавычки:
gci "C:toolsBriss-2.0*" -Filter b*.jar -Recurse
Кавычки заставят PowerShell рассматривать путь как единое целое, а не разбивать его на части.
2. Учитывайте регистр при использовании wildcards:
Если папка называется Briss-2.0, а вы ищете br*, PowerShell её не найдёт. Используйте Br* или параметр -CaseSensitive (если доступен в вашей версии).
3. Проверяйте, какие папки сканируются:
Добавьте -Directory к команде, чтобы увидеть, какие директории попадают под wildcard:
gci C:toolsbr* -Directory
4. Фильтруйте через Where-Object для сложных условий:
gci C:tools -Recurse | Where-Object { $_.Name -like 'b*.jar' }
Это менее эффективно, но даёт больше контроля.

Примеры
# Ищет во всех подпапках C:tools, где имя папки начинается на “Briss-2”
gci "C:toolsBriss-2*" -Filter b*.jar -Recurse
# Альтернатива: явно указать путь к папке lib
gci "C:toolsBriss-2.0libb*.jar" -Recurse
Важно: PowerShell обрабатывает пути с wildcards иначе, чем вы могли привыкнуть в других средах. Всегда проверяйте, какие папки и файлы попадают в выборку, прежде чем использовать команду в скрипте.
Таблица частых ошибок
Ошибка | Почему возникает | Исправление |
gci C:toolsbr* -Filter b*.jar | Wildcard br* не находит папку Briss-2.0 из-за регистра | Использовать Br* или -CaseSensitive |
gci C:toolsbriss-2.0.jar -Recurse | PowerShell ищет файл briss-2.0.jar в подпапках | Указать путь к папке, а не файлу |
Если до сих пор кажется, что PowerShell «глючит», попробуйте упростить команду:
1. Уберите -Recurse и проверьте, что находит команда без рекурсии.
2. Замените wildcards на точные имена папок.
3. Используйте Resolve-Path для отладки путей:
И помните: даже опытные разработчики иногда тратят часы на такие мелочи. Главное – не забывать проверять каждое звено в цепочке команд (а ещё можно выпить кофе и попробовать снова 😉).