2016-02-26 11 views

Antwort

9

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?

+0

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

+0

@jjacek siehe edit – briantist

+1

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' –