about_Pipeline_Chain_Operators
Breve descrizione
Descrive le pipeline di concatenamento con gli &&
operatori e ||
in PowerShell.
Descrizione lunga
A partire da PowerShell 7, PowerShell implementa gli &&
operatori e ||
per concatenare in modo condizionale le pipeline. Questi operatori sono noti in PowerShell come operatori della catena di pipeline e sono simili agli elenchi AND-OR nelle shell POSIX come bash, zsh e sh, nonché simboli di elaborazione condizionale in Windows Command Shell (cmd.exe).
L'operatore &&
esegue la pipeline di destra se la pipeline di sinistra ha avuto esito positivo. Viceversa, l'operatore ||
esegue la pipeline di destra se la pipeline di sinistra ha avuto esito negativo.
Questi operatori usano le variabili $?
e $LASTEXITCODE
per determinare se una pipeline ha avuto esito negativo. Ciò consente di usarli con comandi nativi e non solo con cmdlet o funzioni. Ad esempio:
# 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
Esempi
Due comandi riusciti
Write-Output 'First' && Write-Output 'Second'
First
Second
Il primo comando ha esito negativo, causando l'esecuzione della seconda non
Write-Error 'Bad' && Write-Output 'Second'
Write-Error: Bad
Il primo comando ha esito positivo, quindi il secondo comando non viene eseguito
Write-Output 'First' || Write-Output 'Second'
First
Il primo comando ha esito negativo, quindi il secondo comando viene eseguito
Write-Error 'Bad' || Write-Output 'Second'
Write-Error: Bad
Second
L'esito positivo della pipeline è definito dal valore della variabile, che PowerShell imposta automaticamente dopo l'esecuzione $?
di una pipeline in base allo stato di esecuzione.
Ciò significa che gli operatori della catena di pipeline hanno l'equivalenza seguente:
Test-Command '1' && Test-Command '2'
funziona come
Test-Command '1'; if ($?) { Test-Command '2' }
e
Test-Command '1' || Test-Command '2'
funziona come
Test-Command '1'; if (-not $?) { Test-Command '2' }
Assegnazione da catene di pipeline
L'assegnazione di una variabile da una catena di pipeline accetta la concatenazione di tutte le pipeline della catena:
$result = Write-Output '1' && Write-Output '2'
$result
1
2
Se si verifica un errore di terminazione dello script durante l'assegnazione da una catena di pipeline, l'assegnazione non riesce:
try
{
$result = Write-Output 'Value' && $(throw 'Bad')
}
catch
{
# Do nothing, just squash the error
}
"Result: $result"
Result:
Sintassi dell'operatore e precedenza
A differenza di altri operatori, &&
e ||
operano su pipeline, anziché su espressioni come +
o -and
, ad esempio.
&&
e ||
avere una precedenza inferiore rispetto a piping>
() o reindirizzamento (), ma una precedenza maggiore rispetto agli operatori di processo (&
), assegnazione (|
=
) o punti e virgola (;
). Ciò significa che le pipeline all'interno di una catena di pipeline possono essere reindirizzate singolarmente e che l'intera catena di pipeline può essere in background, assegnata a variabili o separate come istruzioni.
Per usare la sintassi di precedenza inferiore all'interno di una catena di pipeline, prendere in considerazione l'uso delle parentesi (...)
. Analogamente, per incorporare un'istruzione all'interno di una catena di pipeline, è possibile usare una sottoespressione $(...)
. Ciò può risultare utile per combinare comandi nativi con il flusso di controllo:
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
A partire da PowerShell 7, il comportamento di queste sintassi è stato modificato in modo che $?
sia impostato come previsto quando un comando riesce o non riesce tra parentesi o sottoespressione.
Come la maggior parte degli altri operatori in PowerShell, &&
e ||
sono anche associativi a sinistra, ovvero raggruppano da sinistra. Ad esempio:
Get-ChildItem -Path ./file.txt ||
Write-Error "file.txt doesn't exist" &&
Get-Content -Raw ./file.txt
raggruppa come:
(Get-ChildItem -Path ./file.txt || Write-Error "file.txt doesn't exist") &&
Get-Content -Raw ./file.txt
equivalente a:
Get-ChildItem -Path ./file.txt
if (-not $?) { Write-Error "file.txt does not exist" }
if ($?) { Get-Content -Raw ./file.txt }
Interazione degli errori
Gli operatori della catena di pipeline non assorbono errori. Quando un'istruzione in una catena di pipeline genera un errore di terminazione dello script, la catena di pipeline viene terminata.
Ad esempio:
$(throw 'Bad') || Write-Output '2'
Exception: Bad
Anche quando viene rilevato l'errore, la catena di pipeline viene ancora terminata:
try
{
$(throw 'Bad') || Write-Output '2'
}
catch
{
Write-Output "Caught: $_"
}
Write-Output 'Done'
Caught: Bad
Done
Se un errore non termina o termina solo una pipeline, la catena di pipeline continua, rispettando il valore di $?
:
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
Pipeline di concatenamento anziché comandi
Gli operatori della catena di pipeline, in base al nome, possono essere usati per concatenare le pipeline, anziché solo i comandi. Ciò corrisponde al comportamento di altre shell, ma può rendere più difficile determinare:
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
Si noti che Write-Output 'All done!'
non viene eseguito, poiché Test-NotTwo
viene considerato non riuscito dopo aver generato l'errore non terminante.