Сравняване на родител на директория с друга директория в канал 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
@Johannes Rossel хех това е много по-сбито; Благодаря.   -  person tenpn    schedule 29.06.2010


Отговори (2)


Когато сравнявате .NET обекти, има редица фактори. Първо, сравнението може да бъде обикновено сравнение на равенство по референтна стойност, т.е. дали тази променлива препраща към точно същия обект, към който препраща другата променлива. В много случаи (повечето референтни типове) това е поведението по подразбиране за равенство. Има обаче други типове (типове стойности), които правят равенство въз основа на стойността на полетата в обект, напр. DateTime, TimeSpan, Int32, Double и т.н. След това има обекти, които заменят поведението по подразбиране чрез замяна на operator == или и/или замяна на виртуалния метод Equals(). Низът е референтен тип, който отменя тези, за да осигури „базирано на стойност“ равенство.

Вижте дали това върши работа:

$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