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 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 interna 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 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 efter att 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 skriptslutande fel 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, i stället för på uttryck som +
eller -and
, till exempel.
&&
och ||
har lägre prioritet än rörledning (|
) 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 separeras 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 $?
anges som förväntat när ett kommando lyckas eller misslyckas inom parenteser eller underuttryck.
Precis som de flesta andra operatorer i PowerShell &&
och ||
är också vänster-associativa, vilket innebär att de grupperas från vänster. 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 skriptslutande fel avslutas pipelinekedjan.
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 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 kan med deras 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:
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.