Diese mit, wie die Pipeline-Arbeiten zu tun hat. Wenn Sie ein anderes Cmdlet verwenden, wie Write-Verbose
wird es wie erwartet:
$t = "before"
1..2 | Tee-Object -Variable t | Write-Verbose -Verbose
dass Betrachten während einer Pipeline, jede Funktion oder Cmdlets einen Begin
, Process
und End
Block verwenden kann.
Alle Begin
Blöcke werden zuerst ausgeführt, dann wird Process
einmal für jedes Pipelineobjekt und dann alle End
s aufgerufen.
Die Variablenzuweisung muss unbedingt im End
Block erfolgen.
Ab PowerShell v3 können Cmdlets die Pipeline unterbrechen.
Das ist großartig für etwas wie Select-Object -First 1
, weil es bedeutet, dass die gesamte Pipeline nach dem ersten Objekt gestoppt werden kann, anstatt einmal für jedes Element auszuführen, auch wenn der Rest verworfen wird.
Aber es bedeutet auch, dass der End
Block nie ausgeführt wird.
Wenn Sie starten Powershell in v2: powershell.exe -Version 2.0
Und dann Ihr zweites Beispiel ausführen, wird es wie erwartet funktionieren, weil die Pipeline nicht vorzeitig in dieser Version gestoppt werden kann.
Hier ist eine Demonstration:
function F1 {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)]
$o
)
Begin {
Write-Verbose "Begin" -Verbose
}
Process {
Write-Verbose $o -Verbose
$o
}
End {
Write-Verbose "End" -Verbose
}
}
es dann nennen:
1..2 | F1
gegen
1..2 | F1 | Select-Object -First 1
Sie konnten dieses demonstrieren mit ForEach-Object
:
1..2 | ForEach-Object -Begin {
Write-Verbose "Begin" -Verbose
} -Process {
Write-Verbose $_ -Verbose
$_
} -End {
Write-Verbose "End" -Verbose
}
vs.
1..2 | ForEach-Object -Begin {
Write-Verbose "Begin" -Verbose
} -Process {
Write-Verbose $_ -Verbose
$_
} -End {
Write-Verbose "End" -Verbose
} | Select-Object -First 1
Nach the documentation you linked, können Sie den -Wait
Parameter verwenden diese Optimierung zu deaktivieren:
$t = "before"
1..2 | Tee-Object -Variable t | Select-Object -First 1 -Wait
Diese $t
bevölkern, aber vielleicht nicht mit dem Wert, den Sie wollten. Es wird @(1,2)
enthalten, vermutlich weil die -OutVariable
auf Tee-Object
und nicht auf Select-Object
platziert wurde.
Denken Sie daran, dass das "Ergebnis" der Pipeline ist, was von der Ausführung zurückgegeben wird (linke Seite der =
), und das ist in allen Fällen korrekt.
-OutVariable
ist etwas implementiert durch einige Cmdlets, und es muss höchstwahrscheinlich in den End
Block für dieses bestimmte Cmdlet implementiert werden, so dass die Vorhersage dessen, was es geben wird, sehr abhängig von dem Verständnis des Ausführungsflusses der Pipeline ist.
Also, um die Frage in Ihrem Kommentar zu beantworten, scheint es mir, um richtig umgesetzt werden. Verkenne ich deine Behauptung?
In Bezug auf Spezifikationen von "Select-Object -First" (https://technet.microsoft.com/en-us/library/hh849895.aspx) und "Tee-Object -Variable" (https://technet.microsoft .com/de-de/library/hh849937.aspx) Die PowerShell 3+ -Pipeline-Optimierung wurde nicht ordnungsgemäß implementiert. Korrekte Implementierung sollte Ergebnis @ (1) - Strom nach dem ersten Element gebrochen oder @ (1,2) - unberührten Strom. Sind Sie einverstanden? – jjacek
@jjacek siehe edit – briantist
Die erzwungene Reihenfolge der Auswertung (effektives Teilen der Pipeline in zwei) mit Klammern ist eine weitere Option: '(1..2 | tee -variable t) | wählen -erst 1' –