Ist es möglich, Rohr bedingt in Powershell, d.h. führen Sie ein element einer pipeline nur, wenn eine Bedingung erfüllt ist?
Möchte ich etwas wie das hier tun:
<statement> | <filter1> | <filter2> if <condition> | <filter3> | <filter4> | <filter5>
Den Ergebnissen <statement> starten Sie durch <filter1>, dann laufen Sie durch <filter2> erst wenn <Bedingung> erfüllt ist, dann durch die restlichen Filter, unabhängig davon, ob <filter2> angewendet wurde. Dies ist das äquivalent von:
if (<condition>) {
<statement> | <filter1> | <filter2> | <filter3> | <filter4> | <filter5>
} else {
<statement> | <filter1> | <filter3> | <filter4> | <filter5>
}
Dies wäre nützlich bei Funktionen, bei denen ein filter angewendet wird, um die Ergebnismenge nur, wenn ein bestimmter Schalter aufgerufen wurde. Wenn die Auswertung der filter erfolgt früh in einer langen pipeline, schreiben Sie es mit einer äußeren if-block Ergebnisse in eine Menge von Wiederholung von code, vor allem wenn es mehr als eine bedingte filter.
Hier ist ein Beispiel. Die folgende Funktion zeigt die Berechtigungen für ein bestimmtes Konto in ein bestimmtes Verzeichnis-Teilbaum (z.B. Show-AccountPerms \\SERVERX\Marketing DOMAIN\jdoe
gibt einen Bericht von Berechtigungen, die der Benutzer DOMAIN\jdoe hat in den Verzeichnisbaum unter \SERVERX\Marketing).
function Show-AccountPerms {
param (
[parameter(mandatory = $true)]$rootdir,
[parameter(mandatory = $true)]$account,
[switch]$files,
[switch]$inherited
)
gci -r $rootdir `
|where {$_.psiscontainer} `
|foreach {
$dir = $_.fullname
(get-acl $_.pspath).access `
| where {$_.isinherited -eq 'False'} `
|foreach {
if ($_.identityreference -eq $account) {
"{0,-25}{1,-35}{2}" -f $_.identityreference, $_.filesystemrights, $dir
}
}
}
}
Standardmäßig, es zeigt nur explizite Berechtigungen (erzwungen durch die | where {$_.isinherited -eq 'False'}
filter), und nur auf Verzeichnisse (erzwungen durch die |where {$_.psiscontainer}
filter).
Allerdings möchte ich zu ignorieren |where {$_.psiscontainer}
wenn die -Dateien-Schalter aufgerufen wird, und ignorieren | where {$_.isinherited -eq 'False'}
wenn die geerbte Schalter aufgerufen wird. Dies zu erreichen mit dem äußeren, wenn Blöcke vervierfachen sich den code, und fast 75% wäre es Wiederholung. Gibt es einen Weg, um diese Filter in-line, aber anweisen, powershell gelten nur für die Ihnen von der entsprechende Schalter ist falsch?
Bitte beachten Sie, dass dies nur ein Beispiel, also ich bin nicht daran interessiert, irgendwelche workarounds, die spezifisch für diese Funktion. Ich bin auf der Suche nach einer Antwort auf meine Allgemeine Frage bezüglich Rohrleitungen bedingt, nicht eine Lösung, wie dies zu erreichen bestimmte Aufgabe.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie test für beide Bedingungen im filter, so dass das Objekt über die pipeline, wenn entweder eine wahr ist. Wenn dein "Zustand" ist auf der linken Seite des
-or
Betreiber, machen Sie Ergebnis zu$true
wenn Sie nicht möchten, dass Ihre filter-Bedingung getestet.Zur Nutzung Ihrer Beispiel:
wird:
und
wird
Verallgemeinern:
wird:
Select-String <pattern>
nur, wenn die Bedingung wahr ist.| -not <condition> -or <filter2> |
nicht funktioniert, z.B.| -not $switch -or select-string 'sometext' |
. Behalten Sie im Hinterkopf, was "filter" bedeutet, - ein Befehl, der nimmt die pipeline input und sendet die Ergebnisse über die pipeline. Der Zustand test wäre ein Teil des <filter2>, und funktioniert also nur, wenn Sie den filter-Befehl wertet einen Zustand (D. H., ein wo).Ich denke, dass die andere Antwort auf diese Frage verkennt, was verlangt wird.
Die Lösung liegt in der folgenden:
... | %{if($_ -match "Something"){DoSomethingWith $_ }else{$_}} | ...
Was wird dies tun, ist alle Elemente durch, um den nächsten filter, mit AUSNAHME derjenigen, die-match "Etwas", in diesem Fall tut es unterschiedliche Logik. Die Logik kann geändert werden, um es übergeben eine geänderte version der pipeline-element anstelle von einer Funktion.
if (<condition that has nothing to do with $_>) {<pipe $_ through this filter>}
, ansonsten überspringen Sie diesen filter und bewegen Sie auf die nächste Stufe der pipeline. Dieelse {$_}
ist tatsächlich ein workaround für das Letzte Teil, das überspringen der Stufe der pipeline, und sich auf das nächste.Ich denke du meinst so etwas wie das folgende, welches ich gerade erfunden:
Ergebnisse in 2, 4, 6, wenn
$doDouble
ist$true
, und auf$false
es ergibt 1, 2, 3.Der Schlüssel hier ist, dass eine beliebige Rohr-element wie
% { $_ * 2}
gekapselt werden kann, wie ein ScriptBlock wie{$input | % { $_ * 2 } }
ist, und dass es umgewandelt werden kann zurück zu einem Rohr element, indem&
.Ich verwendet http://blogs.msdn.com/b/powershell/archive/2006/12/29/dyi-ternary-operator.aspx für inspiration.
Wichtiger Hinweis. Don ' T verwenden Sie so etwas wie dieses:
Diese Ursachen
%
werden mehrfach ausgeführt, einmal für jedes Objekt in der pipeline.Pipe-If
korrekt ausführt, die%
Befehl nur einmal, und sendet es den gesamten Strom von Objekten.Im obigen Beispiel ist das kein problem. Aber wenn der Befehl
tee bla.txt
dann der Unterschied ist wichtig.&(Pipe-If {<condition>} {$_| <filter> })
ist genau so eine syntax. Ob oder nicht, um eine Funktion zu verwenden (mit wahrscheinlich keine Auswirkung auf die Leistung) hängt vom Kontext ab, und ob man lieberforeach {if (<condition>) {$_ | <filter>} else {$_}
Präferenz.Sorry, ich wollte nicht aufgeben, diese Frage. Die Antworten, die gegeben wurden, waren nicht das, was ich fuhr, aber ich herausgefunden, einen Weg, es zu tun, kurz nach der Veröffentlichung, und kam nicht wieder auf die Website für eine lange Zeit. Da eine Lösung wurde noch nicht gepostet, hier ist was ich kam mit. Es ist nicht ganz das, was ich im Sinn hatte, als ich die Frage gestellt habe, und es ist nicht zu schön, aber anscheinend ist es der einzige Weg, es zu tun:
So, in dem Beispiel die Zeile
geändert
und
geändert
(Ja, normalerweise würde ich schreiben, dass als
|foreach {if ($files) {$_} else {$_ | where {$_.psiscontainer}}}
, und|foreach {if ($inherited) {$_} else {$_ | where {$_.isinherited -eq 'False'}}}
aber ich habe es auf diese Weise für Klarheit.)Ich hatte gehofft, es könnte etwas eleganter, würde das auswerten einer Bedingung vor dem filter einmal, um festzustellen, ob ausführen oder überspringen einer Stufe der pipeline. So etwas wie dieses:
(ein spezieller Fall von
if
, nicht die übliche Bedeutung; ein anderes Schlüsselwort verwendet werden könnte), oder vielleicht$_
wäre ungültig, in dem Zustand, es sei denn, er definiert wird, die außerhalb des aktuellen pipeline, zum Beispiel, wenn die pipeline wird, die in einemswitch
Anweisung$_
im<condition>
finden würde derswitch
Anweisung$_
.Ich denke, ich werde einen feature-Vorschlag an Microsoft. Dies wäre nicht nur der code eleganter, es wäre effizienter, denn wenn es eine built-in Funktion
<condition>
ausgewertet werden konnten einmal für die gesamte pipeline, eher dann testen Sie die gleiche unabhängige Bedingung, die in jeder iteration.Weitere option ist, um eine Globale Präferenz-flag (Typ
System.Management.Automation.ActionPreference
), um dem Benutzer erlauben, um zu bestimmen, ob die pipeline filter etwas tut.Beispielsweise die
$progressPreference
kann auf folgende Werte eingestellt:Diese Einstellung fahne ist dann durch
Write-Progress
zu bestimmen, das gewünschte Verhalten.zum Beispiel, wenn Sie eine pipeline filter
Show-Progress
, zählt, die Elemente und zeigt einen Fortschrittsbalken an, es werden dann nur die Anzeige der Balken, wenn$progressPreference
eingestellt istContinue
.Können Sie verwenden, verhält sich die Konstruktion in Ihrer eigenen pipeline Filter.
Group-Object
), aber nur, wenn ein-Summarize
Schalter vom Benutzer bereitgestellt wird.Dies ist ähnlich wie Marnix Klooster ' s Antwort ist aber einfacher, mit zu arbeiten. Der Vorteil dieser Formulierung gegenüber, dass man in der syntax des code ausgeführt werden kann. Es ist viel näher an eine normale pipeline-block. Im Grunde brauchen Sie nur zu umschließen, was Sie wollen in {} (geschweifte Klammern).
Beachten Sie, dass, Wie Marnix Schrift dies ist eine blockierende Funktion. Die pipeline, die Ergebnisse sind gesammelt in $Input und die Funktion selbst führt nur einmal. Nur $pipeElement code immer ausführt, mehr als einmal, und auch nur dann, wenn die Ausführung stimmt.
Mit dieser Funktion nicht schon definiert sein! Sie können wirklich wirklich definieren innerhalb der Funktion, wo Sie es verwenden möchten, und lassen es verschwinden, wenn Ihre Funktion beendet ist.
Dem ausführen der parameter aktiviert/deaktiviert den Schritt der Ausführung. Jeder Ausdruck mit boolschem Ergebnis funktioniert. Zum Beispiel $(1 -eq 0) funktioniert genauso wie $false.