about_Pipeline_Chain_Operators
Краткое описание
Описывает конвейеры цепочки с &&
||
операторами и операторами в PowerShell.
Подробное описание
Начиная с PowerShell 7, PowerShell реализует &&
конвейеры условной цепочки и ||
операторы. Эти операторы известны в PowerShell как операторы цепочки конвейеров и похожи на списки AND-OR в оболочках POSIX, таких как bash, zsh и sh, а также символы условной обработки в командной оболочке Windows (cmd.exe).
Оператор &&
выполняет конвейер в правой части, если конвейер в левой части был выполнен успешно. И наоборот, оператор ||
выполняет конвейер в правой части, если конвейер в левой части не удалось выполнить.
Для определения того, был ли выполнен конвейер, эти операторы используют переменные $?
и $LASTEXITCODE
. Это позволяет использовать их с собственными командами, а не только с командлетами или функциями. Например:
# 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
Примеры
Две успешные команды
Write-Output 'First' && Write-Output 'Second'
First
Second
Первая команда завершается ошибкой, что приводит к неисполнимой секунде
Write-Error 'Bad' && Write-Output 'Second'
Write-Error: Bad
Первая команда завершается успешно, поэтому вторая команда не выполняется
Write-Output 'First' || Write-Output 'Second'
First
Первая команда завершается ошибкой, поэтому вторая команда выполняется
Write-Error 'Bad' || Write-Output 'Second'
Write-Error: Bad
Second
Успешность конвейера определяется значением переменной $?
, которая PowerShell автоматически задает после выполнения конвейера на основе его состояния выполнения.
Это означает, что операторы цепочки конвейеров имеют следующую эквивалентность:
Test-Command '1' && Test-Command '2'
работает так же, как и
Test-Command '1'; if ($?) { Test-Command '2' }
и
Test-Command '1' || Test-Command '2'
работает так же, как и
Test-Command '1'; if (-not $?) { Test-Command '2' }
Назначение из цепей конвейеров
Назначение переменной из цепочки конвейеров принимает объединение всех конвейеров в цепочке:
$result = Write-Output '1' && Write-Output '2'
$result
1
2
Если при назначении из цепочки конвейера возникает завершающаяся ошибка скрипта, назначение не выполняется:
try
{
$result = Write-Output 'Value' && $(throw 'Bad')
}
catch
{
# Do nothing, just squash the error
}
"Result: $result"
Result:
Синтаксис оператора и приоритет
В отличие от других операторов, &&
а не на конвейерах, а не на выражениях, например-and
+
.||
&&
и ||
имеют более низкий приоритет, чем piping (|
) или перенаправление (>
), но более высокий приоритет, чем операторы заданий (), назначение (&
=
) или точка с запятой (;
). Это означает, что конвейеры в цепочке конвейеров могут быть перенаправлены по отдельности, а все цепочки конвейеров могут быть фоном, назначены переменным или разделены как инструкции.
Чтобы использовать более низкий синтаксис приоритета в цепочке конвейеров, рассмотрите возможность использования круглых скобок (...)
. Аналогичным образом для внедрения инструкции в цепочку конвейера можно использовать вложенные выражения $(...)
. Это может быть полезно для объединения собственных команд с потоком управления:
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
По состоянию на PowerShell 7 поведение этих синтаксисов было изменено таким образом, чтобы $?
он был задан, как ожидалось, когда команда завершается успешно или завершается сбоем в скобках или в подтекстах.
Как и большинство других операторов в PowerShell, &&
а ||
также являются левыми ассоциативными, то есть они группируются слева. Например:
Get-ChildItem -Path ./file.txt ||
Write-Error "file.txt doesn't exist" &&
Get-Content -Raw ./file.txt
будет группироваться как:
(Get-ChildItem -Path ./file.txt || Write-Error "file.txt doesn't exist") &&
Get-Content -Raw ./file.txt
эквивалентен следующему:
Get-ChildItem -Path ./file.txt
if (-not $?) { Write-Error "file.txt does not exist" }
if ($?) { Get-Content -Raw ./file.txt }
Взаимодействие с ошибками
Операторы цепочки конвейеров не поглощают ошибки. Когда инструкция в цепочке конвейера вызывает ошибку, завершающая скрипт, цепочка конвейера завершается.
Например:
$(throw 'Bad') || Write-Output '2'
Exception: Bad
Даже при обнаружении ошибки цепочка конвейеров по-прежнему завершается:
try
{
$(throw 'Bad') || Write-Output '2'
}
catch
{
Write-Output "Caught: $_"
}
Write-Output 'Done'
Caught: Bad
Done
Если ошибка не завершается или завершается только конвейер, цепочка конвейера продолжается, учитывая значение $?
:
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
Цепочка конвейеров, а не команд
Операторы цепочки конвейеров, по их имени, можно использовать для цепочки конвейеров, а не только команд. Это соответствует поведению других оболочк, но может сделать успех более сложным для определения:
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
Обратите внимание, что не выполняется, так как Test-NotTwo
считается, что Write-Output 'All done!'
произошел сбой после создания неустранимой ошибки.
См. также
PowerShell
Обратная связь
Отправить и просмотреть отзыв по