Partager via


about_Pipeline_Chain_Operators

Description courte

Décrit le chaînage de pipelines avec les && opérateurs et || dans PowerShell.

Description longue

À compter de PowerShell 7, PowerShell implémente les && opérateurs et || pour chaîner de manière conditionnelle les pipelines. Ces opérateurs sont connus dans PowerShell en tant qu’opérateurs de chaîne de pipeline et sont similaires aux listes AND-OR dans les interpréteurs de commandes POSIX comme bash, zsh et sh, ainsi qu’aux symboles de traitement conditionnel dans l’interpréteur de commandes Windows (cmd.exe).

L’opérateur && exécute le pipeline droit si l’exécution du pipeline gauche a réussi. Inversement, l’opérateur || exécute le pipeline droit si l’exécution du pipeline gauche a échoué.

Ces opérateurs utilisent les variables $? et $LASTEXITCODE pour déterminer si un pipeline a échoué. Cela vous permet de les utiliser avec des commandes natives, et pas seulement avec des cmdlet ou des fonctions. Par exemple :

# 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

Exemples

Deux commandes réussies

Write-Output 'First' && Write-Output 'Second'
First
Second

La première commande échoue, ce qui entraîne l’échec de l’exécution de la seconde

Write-Error 'Bad' && Write-Output 'Second'
Write-Error: Bad

La première commande réussit, de sorte que la deuxième commande n’est pas exécutée

Write-Output 'First' || Write-Output 'Second'
First

La première commande échoue, la deuxième commande est donc exécutée

Write-Error 'Bad' || Write-Output 'Second'
Write-Error: Bad
Second

La réussite du pipeline est définie par la valeur de la $? variable, que PowerShell définit automatiquement après l’exécution d’un pipeline en fonction de son status d’exécution. Cela signifie que les opérateurs de chaîne de pipeline ont l’équivalence suivante :

Test-Command '1' && Test-Command '2'

fonctionne de la même façon que

Test-Command '1'; if ($?) { Test-Command '2' }

et

Test-Command '1' || Test-Command '2'

fonctionne de la même façon que

Test-Command '1'; if (-not $?) { Test-Command '2' }

Affectation à partir de chaînes de pipeline

L’affectation d’une variable à partir d’une chaîne de pipeline prend la concaténation de tous les pipelines de la chaîne :

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

Si une erreur de fin de script se produit pendant l’affectation à partir d’une chaîne de pipeline, l’affectation ne réussit pas :

try
{
    $result = Write-Output 'Value' && $(throw 'Bad')
}
catch
{
    # Do nothing, just squash the error
}

"Result: $result"
Result:

Syntaxe et priorité de l’opérateur

Contrairement à d’autres opérateurs, && et || fonctionnent sur des pipelines, plutôt que sur des expressions telles que + ou -and, par exemple.

&& et || ont une priorité inférieure à la canalisation (|) ou à la redirection (>), mais une priorité plus élevée que les opérateurs de travail (&), l’affectation (=) ou les points-virgules (;). Cela signifie que les pipelines d’une chaîne de pipeline peuvent être redirigés individuellement et que des chaînes de pipeline entières peuvent être en arrière-plan, affectées à des variables ou séparées sous forme d’instructions.

Pour utiliser la syntaxe de précédence inférieure dans une chaîne de pipeline, envisagez d’utiliser des parenthèses (...). De même, pour incorporer une instruction dans une chaîne de pipeline, une sous-expression $(...) peut être utilisée. Cela peut être utile pour combiner des commandes natives avec un flux de contrôle :

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

À partir de PowerShell 7, le comportement de ces syntaxes a été modifié pour être $? défini comme prévu lorsqu’une commande réussit ou échoue entre parenthèses ou sous-expression.

Comme la plupart des autres opérateurs dans PowerShell, && et || sont également associatifs de gauche, ce qui signifie qu’ils se regroupent à partir de la gauche. Par exemple :

Get-ChildItem -Path ./file.txt ||
    Write-Error "file.txt doesn't exist" &&
    Get-Content -Raw ./file.txt

est groupé en tant que :

(Get-ChildItem -Path ./file.txt || Write-Error "file.txt doesn't exist") &&
    Get-Content -Raw ./file.txt

équivalent à :

Get-ChildItem -Path ./file.txt

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

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

Interaction d’erreur

Les opérateurs de chaîne de pipeline n’absorbent pas les erreurs. Lorsqu’une instruction dans une chaîne de pipeline lève une erreur de fin de script, la chaîne de pipeline est terminée.

Par exemple :

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

Même lorsque l’erreur est interceptée, la chaîne de pipeline est toujours terminée :

try
{
    $(throw 'Bad') || Write-Output '2'
}
catch
{
    Write-Output "Caught: $_"
}
Write-Output 'Done'
Caught: Bad
Done

Si une erreur ne se termine pas ou termine uniquement un pipeline, la chaîne de pipeline continue, en respectant la valeur de $?:

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

Chaînage de pipelines plutôt que de commandes

Les opérateurs de chaîne de pipeline, par leur nom, peuvent être utilisés pour chaîner des pipelines, plutôt que de simplement des commandes. Cela correspond au comportement d’autres interpréteurs de commandes, mais peut rendre la réussite plus difficile à déterminer :

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

Notez que Write-Output 'All done!' n’est pas exécuté, car Test-NotTwo est considéré comme ayant échoué après la génération de l’erreur sans fin.

Voir aussi