Сравнение родительского каталога с другим каталогом в канале where

Представьте, что у меня есть такая структура каталогов:

parentDir\dirA\foo\
parentDir\dirB\foo\
parentDir\dirC\
parentDir\dirD\bar\foo\
parentDir\dirE\foo\
parentDir\dirF\

Я хочу выбрать только те каталоги, которые а) являются непосредственными дочерними элементами parentDir и б) имеют каталог foo в качестве непосредственного дочернего элемента.

Таким образом, каталоги A, B и E подходят, а C, D и F — нет.

Сначала я попробовал этот скрипт powershell:

$rootDir = gi(".")
dir -include "*foo*" -recurse | ? {$_.PSIsContainer -eq $true} | % {$_.Parent} 
    | ? { $_.Parent -eq $rootDir } 

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

Это возвращает пустой список.

Однако, если я изменю последнее предложение where следующим образом:

? { $_.Parent.FullName -eq $rootDir.Fullname }

Это работает, и я получаю правильный вывод каталогов.

Итак, мой вопрос: почему прямое сравнение между объектами каталога не работает? Это может показаться мелочью, но это означает, что в моем понимании объектов powershell есть некоторая дыра.

(Кроме того, не стесняйтесь критиковать мой стиль кодирования powershell в сценариях или указывать более быстрые/более правильные способы сделать это)


person tenpn    schedule 29.06.2010    source источник
comment
Я бы, наверное, написал это как gci | ?{ $_.psiscontainer -and (test-path $_\foo) } ...   -  person Joey    schedule 29.06.2010
comment
@Йоханнес Россель, хех, это намного лаконичнее; Спасибо.   -  person tenpn    schedule 29.06.2010


Ответы (2)


При сравнении объектов .NET учитывается ряд факторов. Во-первых, сравнение может быть простым сравнением равенства ссылок, т. е. ссылается ли эта переменная на тот же самый объект, на который ссылается другая переменная. Во многих случаях (большинство ссылочных типов) это поведение по умолчанию для равенства. Однако существуют другие типы (типы значений), которые выполняют равенство на основе значения полей в объекте, например. DateTime, TimeSpan, Int32, Double и т. д. Затем есть объекты, которые переопределяют поведение по умолчанию, переопределяя оператор == или и/или переопределяя виртуальный метод Equals(). String — это ссылочный тип, который переопределяет их, чтобы обеспечить равенство «на основе значений».

Посмотрите, поможет ли это:

$rootDir = gi .
gci . -r *Foo* | ?{$_.PSIsContainer -and $_.Name -eq 'Tools' -and `
                   $_.Parent.Name -eq $rootDir.Name}
person Keith Hill    schedule 29.06.2010
comment
Спасибо. Я задавался вопросом, является ли -eq ссылочным компаратором или значением, и есть ли какой-то способ сделать его последним. Но из того, что вы говорите, это связано исключительно с классом .Net, который я использую. В будущем мне придется проверить MSDN, чтобы узнать, поддерживает ли используемый класс равенство (в данном случае System.IO.DirectoryInfo). - person tenpn; 30.06.2010

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

-Ойсин

person x0n    schedule 29.06.2010