about_Pipeline_Chain_Operators

Description courte

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

Description longue

À compter de PowerShell 7, PowerShell implémente les opérateurs et || les && implémente sur des pipelines de chaîne conditionnelle. 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 des interpréteurs de commandes POSIX tels que bash, zsh et sh, ainsi que des 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’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, de sorte que la deuxième commande est 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 état 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 précédence des opérateurs

Contrairement à d’autres opérateurs, && et || fonctionnent sur des pipelines, plutôt que sur des expressions comme + 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 au sein d’une chaîne de pipeline peuvent être redirigés individuellement et que l’ensemble des chaînes de pipeline peuvent être en arrière-plan, affectées à des variables ou séparées en tant qu’instructions.

Pour utiliser la syntaxe de précédence inférieure au sein d’une chaîne de pipeline, envisagez l’utilisation de 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

À compter de PowerShell 7, le comportement de ces syntaxes a été modifié de sorte qu’il $? soit 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 regroupent à partir de la gauche. Par exemple :

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

regroupera comme suit :

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

équivaut à :

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 d’une chaîne de pipeline lève une erreur de fin de script, la chaîne de pipeline est arrêté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 arrêtée :

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

Si une erreur n’est pas terminée 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 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 qu’elle Write-Output 'All done!' n’est pas exécutée, car Test-NotTwo elle est considérée comme ayant échoué après avoir généré l’erreur de non-fin.

Voir aussi