about_Pipeline_Chain_Operators

Korte beschrijving

Beschrijft het koppelen van pijplijnen met de && en || operators in PowerShell.

Lange beschrijving

Vanaf PowerShell 7 implementeert PowerShell de && en || operators om pijplijnen voorwaardelijk te koppelen. Deze operators zijn bekend in PowerShell als operatoren voor pijplijnketens en zijn vergelijkbaar met AND-OR-lijsten in POSIX-shells , zoals bash, zsh en sh, evenals symbolen voor voorwaardelijke verwerking in de Windows Command Shell (cmd.exe).

De && operator voert de rechterpijplijn uit als de linkerpijplijn is geslaagd. Omgekeerd voert de || operator de rechterpijplijn uit als de linkerpijplijn is mislukt.

Deze operators gebruiken de $? en $LASTEXITCODE variabelen om te bepalen of een pijplijn is mislukt. Hierdoor kunt u ze gebruiken met systeemeigen opdrachten en niet alleen met cmdlets of functies. Bijvoorbeeld:

# 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

Voorbeelden

Twee geslaagde opdrachten

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

Eerste opdracht mislukt, waardoor de tweede niet wordt uitgevoerd

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

De eerste opdracht slaagt, dus de tweede opdracht wordt niet uitgevoerd

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

Eerste opdracht mislukt, dus de tweede opdracht wordt uitgevoerd

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

Het succes van de pijplijn wordt gedefinieerd door de waarde van de $? variabele, die door PowerShell automatisch wordt ingesteld na het uitvoeren van een pijplijn op basis van de uitvoeringsstatus. Dit betekent dat operators van pijplijnketens de volgende equivalentie hebben:

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

werkt hetzelfde als

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

en

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

werkt hetzelfde als

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

Toewijzing van pijplijnketens

Als u een variabele uit een pijplijnketen toewijst, wordt de samenvoeging van alle pijplijnen in de keten gebruikt:

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

Als er een scripteindingsfout optreedt tijdens de toewijzing vanuit een pijplijnketen, slaagt de toewijzing niet:

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

"Result: $result"
Result:

Operatorsyntaxis en prioriteit

In tegenstelling tot andere operators en &&|| werken ze op pijplijnen, in plaats van op expressies zoals + of -andbijvoorbeeld.

&&en || hebben een lagere prioriteit dan piping () of omleiding (|>), maar een hogere prioriteit dan taakoperators (&), toewijzing (=) of puntkomma's (;). Dit betekent dat pijplijnen binnen een pijplijnketen afzonderlijk kunnen worden omgeleid en dat hele pijplijnketens kunnen worden achtergrond, toegewezen aan variabelen of als instructies kunnen worden gescheiden.

Als u een lagere prioriteitsyntaxis binnen een pijplijnketen wilt gebruiken, kunt u het gebruik van haakjes (...)overwegen. Op dezelfde manier kan een subexpressie $(...) worden gebruikt om een instructie in een pijplijnketen in te sluiten. Dit kan handig zijn voor het combineren van systeemeigen opdrachten met controlestroom:

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

Vanaf PowerShell 7 is het gedrag van deze syntaxis gewijzigd, zodat deze $? wordt ingesteld zoals verwacht wanneer een opdracht slaagt of mislukt tussen haakjes of een subexpressie.

Net als de meeste andere operators in PowerShell en &&|| zijn ze ook links-associatief, wat betekent dat ze van links groeperen. Bijvoorbeeld:

Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist" && Get-Content -Raw ./file.txt

wordt gegroepeerd als:

[Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist"] && Get-Content -Raw ./file.txt

gelijkwaardig zijn aan:

Get-ChildItem -Path ./file.txt

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

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

Foutinteractie

Operators voor pijplijnketens nemen geen fouten op. Wanneer een instructie in een pijplijnketen een scripteindingsfout genereert, wordt de pijplijnketen beëindigd.

Bijvoorbeeld:

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

Zelfs wanneer de fout wordt gepakt, wordt de pijplijnketen nog steeds beëindigd:

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

Als een fout niet is beëindigd of alleen een pijplijn beëindigt, blijft de pijplijnketen doorgaan, waarbij de waarde van $?:

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

Pijplijnen koppelen in plaats van opdrachten

Pijplijnketenoperators kunnen op hun naam worden gebruikt om pijplijnen te koppelen, in plaats van alleen opdrachten. Dit komt overeen met het gedrag van andere shells, maar kan het succes moeilijker maken om te bepalen:

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

Houd er rekening mee dat Write-Output 'All done!' deze niet wordt uitgevoerd, omdat Test-NotTwo deze wordt geacht te zijn mislukt nadat de niet-afsluitfout is gegenereerd.

Zie ook