about_Pipeline_Chain_Operators

Krátký popis

Popisuje řetězení kanálů s && operátory a || operátory v PowerShellu.

Dlouhý popis

Počínaje PowerShellem 7 powershell implementuje operátory && a || operátory do podmíněně zřetězených kanálů. Tyto operátory jsou známé v PowerShellu jako operátory řetězu kanálů a jsou podobné seznamům AND-OR v prostředích POSIX, jako je bash, zsh a sh, a také symboly podmíněného zpracování v prostředí Windows Command Shell (cmd.exe).

Operátor && spustí kanál zprava, pokud byl kanál vlevo úspěšný. Naopak operátor spustí kanál vpravo, || pokud kanál vlevo selhal.

Tyto operátory používají $? proměnné k $LASTEXITCODE určení, jestli kanál selhal. To vám umožní používat je s nativními příkazy, nejen s rutinami nebo funkcemi. Příklad:

# 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

Příklady

Dva úspěšné příkazy

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

První příkaz selže, což způsobí, že se druhý příkaz nespustí.

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

První příkaz je úspěšný, takže druhý příkaz se nespustí.

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

První příkaz selže, takže se spustí druhý příkaz.

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

Úspěch kanálu je definován hodnotou $? proměnné, kterou PowerShell automaticky nastaví po spuštění kanálu na základě jeho stavu spuštění. To znamená, že operátory řetězu kanálů mají následující ekvivalenci:

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

funguje stejně jako

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

a

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

funguje stejně jako

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

Přiřazení z řetězů kanálů

Přiřazení proměnné z řetězu kanálů přebírá zřetězení všech kanálů v řetězci:

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

Pokud během přiřazování z řetězu kanálů dojde k chybě ukončující skript, přiřazení nebude úspěšné:

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

"Result: $result"
Result:

Syntaxe a priorita operátoru

Na rozdíl od jiných operátorů && a || pracují s kanály, nikoli s výrazy jako + nebo -and, například.

&& a || mají nižší prioritu než potrubí (|) nebo přesměrování (>), ale vyšší prioritu než operátory úloh (&), přiřazení (=) nebo středníky (;). To znamená, že kanály v rámci řetězu kanálů je možné jednotlivě přesměrovat a že celé řetězy kanálů můžou být na pozadí, přiřazené proměnným nebo oddělené jako příkazy.

Pokud chcete v řetězu kanálů použít syntaxi s nižší prioritou, zvažte použití závorek (...). Podobně lze k vložení příkazu do řetězu kanálů použít dílčí výraz $(...) . To může být užitečné pro kombinování nativních příkazů s tokem řízení:

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

Od PowerShellu 7 se chování těchto syntaxí změnilo tak, aby $? se nastavovalo podle očekávání, když se příkaz úspěšně nebo selže v závorkách nebo podvýrazu.

Stejně jako většina ostatních operátorů v PowerShellu && a || jsou také asociativní zleva, což znamená, že seskupují zleva. Příklad:

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

seskupí jako:

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

odpovídá:

Get-ChildItem -Path ./file.txt

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

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

Interakce s chybami

Operátory řetězu kanálů nepohlcují chyby. Když příkaz v řetězu kanálu vyvolá chybu ukončující skript, řetězec kanálu se ukončí.

Příklad:

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

I když dojde k zachycení chyby, řetězec kanálu se stále ukončí:

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

Pokud je chyba neukončující nebo ukončí kanál, řetězec kanálu pokračuje a respektuje hodnotu $?:

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

Řetězení kanálů místo příkazů

Operátory řetězu kanálů se podle jejich názvu dají použít ke zřetězování kanálů, nikoli jenom příkazů. To odpovídá chování jiných prostředí, ale může ztížit určení úspěchu:

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

Všimněte si, že Write-Output 'All done!' se nespustí, protože Test-NotTwo se považuje za neúspěšné po vygenerování neukončující chyby.

Viz také