PowerShell équivalent de LINQ Tout()?
Je voudrais trouver tous les répertoires au plus haut niveau de l'emplacement du script qui sont stockés dans la subversion.
En C#, il serait quelque chose comme ceci
Directory.GetDirectories(".")
.Where(d=>Directories.GetDirectories(d)
.Any(x => x == "_svn" || ".svn"));
Je vais avoir un peu de difficulté à trouver l'équivalent des "()" dans PowerShell, et je ne veux pas passer par la maladresse de l'appel de la méthode d'extension.
Jusqu'à présent, j'ai obtenu ceci:
Get-ChildItem | ? {$_.PsIsContainer} | Get-ChildItem -force | ? {$_.PsIsContainer -and $_.Name -eq "_svn" -or $_.Name -eq ".svn"
Ce me trouve le svn
répertoires eux-mêmes, mais pas de leurs répertoires parents - qui est ce que je veux. Les points de Bonus si vous pouvez me dire pourquoi l'ajout de
| Select-Object {$_.Directory}
à la fin de la liste des commandes affiche simplement une séquence de lignes blanches.
Vous devez vous connecter pour publier un commentaire.
À répondre à la immédiate question avec PowerShell v3+ solution:
-Directory
les limites de la correspond à des répertoires,-Recurse -Depth 2
se répète jusqu'à trois niveaux (enfants, petits-enfants et arrière-petits-enfants),Include
permet de spécifier plusieurs (nom de fichier-composant) les filtres, et.Parent.FullName
retourne le chemin complet de la parent dirs. de la correspondance dirs., à l'aide de membre de l'énumération (implicitement l'accès à une collection de éléments " propriétés).Comme pour la question bonus:
select-object {$_.Directory}
ne fonctionne pas,parce que le
\[Système.IO.DirectoryInfo\]
instances renvoyé parGet-ChildItem
ont pas.Directory
propriété, seulement un.Parent
bien;Select-Object -ExpandProperty Parent
doit avoir été utilisé.En plus de ne revenant à la propriété valeur d'intérêt,
-ExpandProperty
applique également à l'existence de la propriété. En revanche,Select-Object {$_.Directory}
renvoie une objet personnalisé avec une propriété littéralement nommé$_.Directory
, dont la valeur est$null
, étant donné que les objets d'entrée ont pas.Directory
de la propriété; ces$null
valeurs impression que les lignes vides dans la console.Comme pour les plus général question sur un PowerShell équivalent à LINQ est
.Tout()
méthode, ce qui indique [avec un résultat Booléen] si une énumérable (collection) est l'un des éléments à toutes /tous les éléments de satisfaire à une condition donnée:Nativement, PowerShell offre pas équivalente, mais le comportement peut être émulé:
À l'aide de la PowerShell v4+
.Where()
méthode de collecte de:Mise en garde: Ce nécessite la collecte de l'ensemble de la collection d'entrée dans la mémoire de la première, ce qui peut être problématique avec les grandes collections et/ou de longue durée les commandes d'entrée.
...
représente la commande de l'intérêt, et$_ ...
la condition d'intérêt, appliquée à chaque entrée de l'objet, où PowerShell automatique$_
variable se réfère à l'entrée de l'objet à portée de main; argument'First'
assure que la méthode renvoie une fois le premier match a été trouvé.Par exemple:
À l'aide de la pipeline: Tester si une commande a produit au moins un objet de sortie [correspondant à une condition]:
La avantage d'un pipeline-solution à base d' est qu'il peut loi sur une sortie de la commande un par un, à mesure qu'elle est produite, sans avoir à recueillir l'ensemble de la sortie dans la mémoire de la première.
Si vous n'avez pas l'esprit que tous objets sont énumérés - même si vous n'en avez que si il y a au moins un - utilisation Paolo Tedesco est utile d'extension à JaredPar de réponse utile.
L'inconvénient de cette approche est que vous devez attendre pour un (potentiellement de longue durée) de commande de terminer la production de tous objets de sortie, même si - logiquement - la détermination de savoir si il y a tout objets de sortie peut être faite dès que le première objet est reçu.
Si vous voulez quitter le pipeline dès que un [correspondance] objet a été rencontré, vous avez deux options:
[Ad-hoc: Facile à comprendre, mais difficile à mettre en œuvre]
Placez le pipeline dans une boucle factice et utilisation
break
de sortir de la canalisation et que la boucle (...
représente la commande dont la sortie à tester, et$_ ...
match de l'état):[Utiliser PowerShell v3+ autonome de la fonction d'utilité qui est non trivial à mettre en œuvre]
Voir la mise en œuvre de fonction
Test-Any
ci-dessous.Il peut être ajouté à des scripts ou, pour une utilisation dans des sessions interactives, à votre
$PROFILE
fichier.PowerShell v3+: l'optimisation de l' fonction d'utilité
Test-Any
La fonction est non trivial, parce que de Windows PowerShell v5.1, PowerShell de Base v6, il n'y a pas de direct façon de sortir d'un pipeline prématurément, donc une solution basée sur .NET réflexion et d'un type privé est actuellement nécessaire.
Si vous êtes d'accord qu'il devrait y avoir une telle fonctionnalité, prendre part à la conversation sur GitHub.
if (-not $Filter -or (Foreach-Object $Filter -InputObject $InputObject))
par défaut à true si$Filter
n'a pas été spécifiée, et sinon évalue le filtre (bloc de script) avec l'objet à portée de main.ForEach-Object
pour évaluer le filtre bloc de script assure que$_
se lie à l'objet de pipeline actuel dans tous scénarios, comme l'a démontré PetSerAl's réponse utile ici.La
(Add-Type ...
instruction utilise ad-hoc de type créé avec le code C# qui utilise la réflexion pour lancer la même exception queSelect-Object -First
(PowerShell v3+) utilise en interne pour arrêter le cours, à savoir[System.Management.Automation.StopUpstreamCommandsException]
, qui, comme de PowerShell v5 est encore un privé type.Arrière-plan ici:
http://powershell.com/cs/blogs/tobias/archive/2010/01/01/cancelling-a-pipeline.aspx
Un grand merci à PetSerAl pour contribuer à ce code dans les commentaires.
Exemples:
PS> @() | Test-Any
false
PS> Get-EventLog Application | Test-Any # should return *right away*
true
PS> 1, 2, 3 | Test-Any { $_ -gt 1 } # see if any object is > 1
true
Informations d'arrière-plan
JaredPar de réponse utile et Paolo Tedesco est utile d'extension tomber à court dans un sens: ils ne doivent pas quitter le pipeline, une fois qu'une correspondance a été trouvée, ce qui peut être un élément important de l'optimisation.
Malheureusement, même en PowerShell v5, il n'y a pas de manière directe à la sortie d'un pipeline prématurément.
Si vous êtes d'accord qu'il devrait y avoir une telle fonctionnalité, prendre part à la conversation sur GitHub.
Un naïf optimisation de JaredPar réponse fait raccourcit le code:
process
bloc est seulement si il existe au moins un élément dans le pipeline.process
bloc est encore entré, avec$_
ensemble de$null
, afin de l'appelantTest-Any
à l'extérieur d'un pipeline unhelpfully retourne$true
. Afin de distinguer entre$null | Test-Any
etTest-Any
, vérifiez$MyInvocation.ExpectingInput
, qui est$true
seulement dans le pipeline: Merci, PetSerAlfunction Test-Any() { process { $MyInvocation.ExpectingInput; break } end { $false } }
$true
, écrit dans le flux de sortie, les signaux d'au moins un objet a été trouvé.break
puis s'arrête le pipeline et empêche donc superflu de traitement d'objets supplémentaires. TOUTEFOIS, IL SORT un ancêtre BOUCLE -break
n'est PAS conçu pour la sortie d'un PIPELINEMerci, PetSerAl.
return
serait tout simplement de passer à la prochaine objet d'entrée.Depuis le
process
bloc inconditionnelle exécutebreak
, leend
bloc n'est atteint que si laprocess
bloc n'a jamais été saisi, ce qui implique un vide pipeline, donc$false
est écrit dans le flux de sortie de signal.Malheureusement, il n'existe pas d'équivalent dans PowerShell. J'ai écrit un billet de blog à ce sujet avec une suggestion pour un usage général, Test-Toute fonction /filtre.
Blog: Il n'y a rien dans ce pipeline?
Une variation sur @JaredPar de réponse, afin d'inclure le critère de la
Test-Any
filtre:Maintenant, je peux écrire "tout" des tests comme
if
déclaration suffit de direif (& $EvaluateCondition $ObjectToTest) { $any = $true }
& $EvaluateCondition $ObjectToTest
ne lie pas l'objet de$_
. La vôtre exemples de travaux, juste parce que le référencement$_
de parent, ce qui seraitTest-Any
champ d'application dans le cas de la fonction définie et exécutée dans le même module ou dans l'état global. Mais si la fonction définie dans un module et utilisé à partir d'un autre module de partir de l'état global, que vous avez tort valeur dans$_
. Vous devriez utiliser quelque chose comme ceci:ForEach-Object $EvaluateCondition -InputObject $ObjectToTest
.Test-Any
pas nécessaire d'être parent pour$EvaluateCondition
bloc de script.Vous pouvez utiliser l'original LINQ
Any
:$list
à être pleinement dans la mémoire déjà, qui va à l'encontre de l'objectif de l'aide de l'streaming PowerShell pipeline: les applets de commande PowerShell n'émettent pas de paresseuxIEnumerable
s, ils émettent des objets un par un pour le pipeline. Si vous passez un applet de commande d'appel de la sortie d'une .Méthode NETTE, cet appel a pour exécuter jusqu'à la fin en premier, ce qui signifie que vous pourriez attendre longtemps et de perdre beaucoup de mémoire avant d'obtenir le résultat; envisager[Linq.Enumerable]::Any((Get-ChildItem / -Recurse))
, par exemple (suite dans le prochain commentaire).(...).Count -gt 0
- pas besoin de LINQ; ce dernier ne pouvait qu'aider s'il vous est arrivé d'appeler un .NET une méthode qui retourne un paresseux énumérable.Mon approche était maintenant:
La raison pour laquelle
ne retourne pas quelque chose d'utile, est qu'il n'est pas sur un
DirectoryInfo
objet. Au moins pas dans mon PowerShell.À élaborer votre propre réponse: PowerShell peut traiter la plupart des non-vide collections
$true
, de sorte que vous pouvez tout simplement faire:Get-ChildItem
renvoie à la foisFileInfo
etDirectoryInfo
objets 🙂Il est en fait assez simple - il suffit de sélectionner la première tranche de vrai (formaté pour plus de clarté):
Autre façon:
[bool]
casting au top depuis que vous êtes déjà la sélection de la première d'une énumération debool
sforeach { $true }
à la fin (après leselect
) et le prédicat danswhere
comme d'habitude, plutôt que de combiner les deux.($source | where { <predicate> } | foreach { $true } | select -first 1)
. Ceci élimine le jette, le rend plus explicite de ce que vous essayez de revenir, et met le prédicat dans une plus attendus de la tuyauterie.[bool]($source | where {<predicate>} | select -first 1 | foreach {$true})
; signifie que vous ne ne leforeach
pour 1 élément, pas tous.J'ai fini par le faire avec un count:
$true
(à l'exception de celui qui contient$false
comme le seul élément, mais ce n'est pas l'intérêt ici). Aussi votre test est raté, car la priorité de-and
et-or
signifie que vous attraper fichiers qui se trouvent être nommé".svn"
trop, depuis lePSIsContainer
test ne s'applique que lorsque le nom correspond à"_svn"
.Vous pouvez serrer cette un peu:
Note de passage de $__.Nom de la imbriquée gci est inutile. En passant c' $_ est suffisante.
Je recommande la solution suivante:
C'est la meilleure méthode que j'ai trouvé à ce jour (ne pas répéter sur tous les éléments si déjà trouvé un vrai, et de ne pas rompre le pipeline):
De LINQ Tout() équivalent en PowerShell
Il est possible d'utiliser un pare-$input variable qui contient l'ensemble du pipeline dans la portée de la fonction.
Donc, le code pourrait ressembler à la suivante:
Je pense que la meilleure réponse est ici la fonction proposée par @JaredPar, mais si vous aimez les one-liners que je fais, je voudrais proposer la suite
Any
one-liner:%{ $match = $false }{ $match = $match -or YOUR_CONDITION }{ $match }
vérifie qu'au moins un élément de match condition.Une note généralement la Tout opération évalue le tableau jusqu'à trouver le premier élément correspondant à l'état. Mais ce code évalue tous les éléments.
Juste de mentionner, vous pouvez facilement ajuster de devenir
All
one-liner:%{ $match = $false }{ $match = $match -and YOUR_CONDITION }{ $match }
vérifie que tous les éléments correspondent condition.Avis, que de vérifier Tout ce que vous avez besoin
-or
et de vérifier Tout ce que vous devez-and
.