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 doesn't exist" &&
Get-Content -Raw ./file.txt
groepeert als:
(Get-ChildItem -Path ./file.txt || Write-Error "file.txt doesn't 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.