Freigeben über


about_Pipeline_Chain_Operators

Kurze Beschreibung

Beschreibt das Verketten von Pipelines mit den && Operatoren und || in PowerShell.

Lange Beschreibung

Ab PowerShell 7 implementiert PowerShell die && Operatoren und || zum bedingten Verketten von Pipelines. Diese Operatoren sind in PowerShell als Pipelinekettenoperatoren bekannt und ähneln AND-OR-Listen in POSIX-Shells wie bash, zsh und sh sowie Symbolen für die bedingte Verarbeitung in der Windows-Befehlsshell (cmd.exe).

Der Operator && führt die rechte Pipeline aus, wenn die linke Pipeline erfolgreich war. Dagegen führt der Operator || die rechte Pipeline aus, wenn die linke Pipeline fehlgeschlagen ist.

Diese Operatoren verwenden die Variablen $? und $LASTEXITCODE, um zu bestimmen, ob eine Pipeline fehlgeschlagen ist. Dadurch können Sie sie mit nativen Befehlen und nicht bloß mit Cmdlets oder Funktionen verwenden. Beispiel:

# Create an SSH key pair - if successful copy the public key to clipboard
ssh-keygen -t rsa -b 2048 && Get-Content -Raw ~\.ssh\id_rsa.pub | clip

Beispiele

Zwei erfolgreiche Befehle

Write-Output 'First' && Write-Output 'Second'
First
Second

Der erste Befehl schlägt fehl, sodass der zweite nicht ausgeführt wird.

Write-Error 'Bad' && Write-Output 'Second'
Write-Error: Bad

Der erste Befehl ist erfolgreich, sodass der zweite Befehl nicht ausgeführt wird.

Write-Output 'First' || Write-Output 'Second'
First

Der erste Befehl schlägt fehl, sodass der zweite Befehl ausgeführt wird.

Write-Error 'Bad' || Write-Output 'Second'
Write-Error: Bad
Second

Pipelineerfolg wird durch den Wert der Variablen definiert, den $? PowerShell automatisch festlegt, nachdem eine Pipeline basierend auf deren Ausführung status ausgeführt wurde. Dies bedeutet, dass Pipelinekettenoperatoren die folgende Äquivalenz aufweisen:

Test-Command '1' && Test-Command '2'

funktioniert genauso wie

Test-Command '1'; if ($?) { Test-Command '2' }

und

Test-Command '1' || Test-Command '2'

funktioniert genauso wie

Test-Command '1'; if (-not $?) { Test-Command '2' }

Zuweisung aus Pipelineketten

Das Zuweisen einer Variablen aus einer Pipelinekette erfordert die Verkettung aller Pipelines in der Kette:

$result = Write-Output '1' && Write-Output '2'
$result
1
2

Wenn während der Zuweisung aus einer Pipelinekette ein Skriptabbruchfehler auftritt, ist die Zuweisung nicht erfolgreich:

try
{
    $result = Write-Output 'Value' && $(throw 'Bad')
}
catch
{
    # Do nothing, just squash the error
}

"Result: $result"
Result:

Operatorsyntax und Rangfolge

Im Gegensatz zu anderen Operatoren &&|| und werden mit Pipelines und nicht mit Ausdrücken wie + oder -andausgeführt, z. B. .

&& und || haben eine niedrigere Rangfolge als Piping (|) oder Umleitung (>), aber eine höhere Rangfolge als Auftragsoperatoren (&), Zuordnung (=) oder Semikolons (;). Dies bedeutet, dass Pipelines innerhalb einer Pipelinekette einzeln umgeleitet werden können und dass ganze Pipelineketten hintergrundgebunden, Variablen zugewiesen oder als Anweisungen getrennt werden können.

Um eine niedrigere Rangfolgensyntax innerhalb einer Pipelinekette zu verwenden, sollten Sie die Verwendung von Klammern (...)in Betracht ziehen. Analog zum Einbetten einer Anweisung in eine Pipelinekette kann ein Teilausdruck $(...) verwendet werden. Dies kann nützlich sein, um systemeigene Befehle mit Ablaufsteuerung zu kombinieren:

foreach ($file in 'file1','file2','file3')
{
    # When find succeeds, the loop breaks
    find $file && Write-Output "Found $file" && $(break)
}
find: file1: No such file or directory
file2
Found file2

Ab PowerShell 7 wurde das Verhalten dieser Syntaxen so geändert, dass wie erwartet festgelegt wird, $? wenn ein Befehl erfolgreich ist oder in Klammern oder einem Teilausdruck fehlschlägt.

Wie die meisten anderen Operatoren in PowerShell && sind auch linksassoziativ||, d. h. sie gruppieren von links. Beispiel:

Get-ChildItem -Path ./file.txt ||
    Write-Error "file.txt doesn't exist" &&
    Get-Content -Raw ./file.txt

gruppiert sich wie folgt:

(Get-ChildItem -Path ./file.txt || Write-Error "file.txt doesn't exist") &&
    Get-Content -Raw ./file.txt

entspricht:

Get-ChildItem -Path ./file.txt

if (-not $?) { Write-Error "file.txt does not exist" }

if ($?) { Get-Content -Raw ./file.txt }

Fehlerinteraktion

Pipelinekettenoperatoren absorbieren keine Fehler. Wenn eine Anweisung in einer Pipelinekette einen Skriptabschlussfehler auslöst, wird die Pipelinekette beendet.

Beispiel:

$(throw 'Bad') || Write-Output '2'
Exception: Bad

Auch wenn der Fehler abgefangen wird, wird die Pipelinekette weiterhin beendet:

try
{
    $(throw 'Bad') || Write-Output '2'
}
catch
{
    Write-Output "Caught: $_"
}
Write-Output 'Done'
Caught: Bad
Done

Wenn ein Fehler nicht beendet wird oder nur eine Pipeline beendet wird, wird die Pipelinekette unter Berücksichtigung des Werts von $?fortgesetzt:

function Test-NonTerminatingError
{
    [CmdletBinding()]
    param()

    $exception = [System.Exception]::new('BAD')
    $errorId = 'BAD'
    $errorCategory = 'NotSpecified'

    $errorRecord = [System.Management.Automation.ErrorRecord]::new(
        $exception, $errorId, $errorCategory, $null
    )

    $PSCmdlet.WriteError($errorRecord)
}

Test-NonTerminatingError || Write-Output 'Second'
Test-NonTerminatingError: BAD
Second

Verketten von Pipelines anstelle von Befehlen

Pipelinekettenoperatoren können mit ihrem Namen anstelle von Befehlen zum Verketten von Pipelines verwendet werden. Dies entspricht dem Verhalten anderer Shells, kann jedoch die Ermittlung von Erfolg erschweren:

function Test-NotTwo
{
    [CmdletBinding()]
    param(
      [Parameter(ValueFromPipeline)]
      $Input
    )

    process
    {
        if ($Input -ne 2)
        {
            return $Input
        }

        $exception = [System.Exception]::new('Input is 2')
        $errorId = 'InputTwo'
        $errorCategory = 'InvalidData'

        $errorRecord = [System.Management.Automation.ErrorRecord]::new(
            $exception, $errorId, $errorCategory, $null
        )

        $PSCmdlet.WriteError($errorRecord)
    }
}

1,2,3 | Test-NotTwo && Write-Output 'All done!'
1
Test-NotTwo : Input is 2
3

Beachten Sie, dass Write-Output 'All done!' nicht ausgeführt wird, da Test-NotTwo nach dem Generieren des nicht beendeten Fehlers als fehlgeschlagen gilt.

Weitere Informationen