Delen via


about_Pipeline_Chain_Operators

Korte beschrijving

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

Lange beschrijving

Vanaf PowerShell 7 implementeert PowerShell de && operators en || om pijplijnen voorwaardelijk te koppelen. Deze operators staan in PowerShell bekend als pijplijnketenoperators en zijn vergelijkbaar met EN-OR-lijsten in POSIX-shells zoals bash, zsh en sh, evenals symbolen voor voorwaardelijke verwerking in de Windows-opdrachtshell (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 $? variabelen en $LASTEXITCODE 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

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 pijplijnketenoperators de volgende gelijkwaardigheid 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 vanuit pijplijnketens

Als u een variabele uit een pijplijnketen toewijst, worden alle pijplijnen in de keten samengevoegd:

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

Als er een fout optreedt bij het beëindigen van scripts 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:

Syntaxis en prioriteit van operator

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

&& 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 volledige pijplijnketens op de achtergrond kunnen worden geplaatst, kunnen worden toegewezen aan variabelen of kunnen worden gescheiden als instructies.

Als u een lagere prioriteitsyntaxis wilt gebruiken binnen een pijplijnketen, 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 een besturingsstroom:

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 zijn && ze || ook links-associatief, wat betekent dat ze van links worden gegroepeerd. Bijvoorbeeld:

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

groepeert als:

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

gelijk zijn aan:

Get-ChildItem -Path ./file.txt

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

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

Foutinteractie

Operators van pijplijnketens absorberen geen fouten. Wanneer een instructie in een pijplijnketen een scriptbeëindigingsfout genereert, wordt de pijplijnketen beëindigd.

Bijvoorbeeld:

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

Zelfs wanneer de fout is ondervangen, 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 of alleen een pijplijn beëindigt, wordt de pijplijnketen voortgezet met inachtneming van 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

Operators van pijplijnketens kunnen op basis van 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 moeilijker maken om succes 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!' niet wordt uitgevoerd, omdat Test-NotTwo wordt beschouwd als mislukt na het genereren van de niet-afsluitfout.

Zie ook