about_Pipeline_Chain_Operators

Kort beskrivning

Beskriver länkningspipelines med && operatorerna och || i PowerShell.

Lång beskrivning

Från och med PowerShell 7 implementerar PowerShell operatorerna && och || för att villkorligt länka pipelines. Dessa operatorer är kända i PowerShell som pipelinekedjeoperatorer och liknar AND-OR-listor i POSIX-gränssnitt som bash, zsh och sh, samt villkorsstyrda bearbetningssymboler i Windows Command Shell (cmd.exe).

Operatorn && kör den högra pipelinen om den vänstra pipelinen lyckades. Omvänt kör operatorn || den högra pipelinen om den vänstra pipelinen misslyckades.

Dessa operatorer använder variablerna $? och $LASTEXITCODE för att avgöra om en pipeline misslyckades. På så sätt kan du använda dem med inbyggda kommandon och inte bara med cmdletar eller funktioner. Till exempel:

# 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

Exempel

Två lyckade kommandon

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

Det första kommandot misslyckas, vilket gör att andra inte körs

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

Det första kommandot lyckas, så det andra kommandot körs inte

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

Det första kommandot misslyckas, så det andra kommandot körs

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

Pipelineframgång definieras av värdet för variabeln $? , som PowerShell automatiskt anger när en pipeline har körts baserat på dess körningsstatus. Det innebär att pipelinekedjeoperatorer har följande likvärdighet:

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

fungerar på samma sätt som

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

och

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

fungerar på samma sätt som

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

Tilldelning från pipelinekedjor

När du tilldelar en variabel från en pipelinekedja sammanfogas alla pipelines i kedjan:

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

Om ett skriptslutfel inträffar under tilldelningen från en pipelinekedja lyckas inte tilldelningen:

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

"Result: $result"
Result:

Operatorsyntax och prioritet

Till skillnad från andra operatorer && , och || fungerar på pipelines, snarare än på uttryck som + eller -and, till exempel.

&& och || har lägre prioritet än rördragning (|) eller omdirigering (>), men högre prioritet än jobboperatorer (&), tilldelning (=) eller semikolon (;). Det innebär att pipelines i en pipelinekedja kan omdirigeras individuellt och att hela pipelinekedjor kan vara bakgrundskopplade, tilldelade till variabler eller avgränsade som instruktioner.

Om du vill använda lägre prioritetssyntax i en pipelinekedja bör du överväga att använda parenteser (...). På samma sätt kan en underuttryck $(...) användas för att bädda in en -instruktion i en pipelinekedja. Detta kan vara användbart för att kombinera interna kommandon med kontrollflöde:

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

Från och med PowerShell 7 har beteendet för dessa syntaxer ändrats så att det $? anges som förväntat när ett kommando lyckas eller misslyckas inom parenteser eller underuttryck.

Liksom de flesta andra operatorer i PowerShell && , och || är också vänster associativa, vilket innebär att de grupperas från vänster. Till exempel:

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

grupperas som:

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

motsvarar:

Get-ChildItem -Path ./file.txt

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

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

Felinteraktion

Pipelinekedjeoperatorer absorberar inte fel. När en instruktion i en pipelinekedja utlöser ett skriptslutfel avslutas pipelinekedjan.

Till exempel:

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

Även när felet fångas avslutas pipelinekedjan fortfarande:

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

Om ett fel inte avslutas eller bara avslutar en pipeline fortsätter pipelinekedjan med respekt för värdet för $?:

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

Länka pipelines i stället för kommandon

Pipelinekedjeoperatorer kan med sitt namn användas för att länka pipelines i stället för bara kommandon. Detta matchar beteendet för andra gränssnitt, men kan göra det svårare att avgöra om det går att lyckas:

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

Observera att Write-Output 'All done!' inte har körts eftersom Test-NotTwo anses ha misslyckats efter att det icke-avslutande felet har genererats.

Se även