about_Pipeline_Chain_Operators
Kort beskrivning
Beskriver länkning av pipelines med operatorerna && och || i PowerShell.
Lång beskrivning
Från och med PowerShell 7 implementerar PowerShell operatorerna && och || för att villkorligt kedja 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 symboler för villkorsstyrd bearbetning i Windows-kommandogränssnittet (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. 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 det 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
Pipeline lyckades definieras av värdet för variabeln $? , som PowerShell automatiskt anger efter att ha kört en pipeline 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 ha bakgrund, tilldelas variabler eller avgränsas 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 ett underuttryck.
Precis som de flesta andra operatorer i PowerShell && och || är också vänster-associativa, vilket innebär att de grupperar från vänster. Exempel:
Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist" && Get-Content -Raw ./file.txt
grupperas som:
[Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not 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 genererar ett skriptslutfel avslutas pipelinekedjan.
Exempel:
$(throw 'Bad') || Write-Output '2'
Exception: Bad
Även om 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 och respekterar 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, efter deras namn, kan användas för att kedja 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:
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 körs eftersom Test-NotTwo anses ha misslyckats efter att det icke-avslutande felet har genererats.