From e1e3c74e0f5cb60626f30ca5140ae414f86d75b7 Mon Sep 17 00:00:00 2001 From: Rob Holt Date: Mon, 30 Sep 2019 15:18:51 -0700 Subject: [PATCH 1/8] Add pipeline chain doc, add to operators doc --- .../About/about_Operators.md | 16 + .../About/about_Pipeline_Chain_Operators.md | 281 ++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md index 3169673d46af..3fa0740ad2b9 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md @@ -374,6 +374,22 @@ Get-Process | Get-Member Get-PSSnapin | Where-Object {$_.vendor -ne "Microsoft"} ``` +#### Pipeline chain operators `&&` and `||` + +Conditionally execute the right-hand side pipeline +based on the success of the left-hand side pipeline. + +```powershell +# If Get-Process successfully finds a process called notepad, +# Stop-Process -Name notepad is called +Get-Process notepad && Stop-Process -Name notepad +``` + +```powershell +# If npm install fails, the node_modules directory is removed +npm install || Remove-Item -Recurse ./node_modules +``` + #### Property dereferences operator `.` Accesses the properties and methods of an object. diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md new file mode 100644 index 000000000000..339ce6223bba --- /dev/null +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -0,0 +1,281 @@ +--- +ms.date: 09/30/2019 +schema: 2.0.0 +locale: en-us +keywords: powershell,cmdlet +title: about_Pipeline_Chain_Operators +--- + +# About Pipeline Chain Operators + +## Short description + +Describes chaining pipelines with the `&&` and `||` operators in PowerShell. + +## Long description + +From PowerShell 7, PowerShell implements the `&&` and `||` operators +to conditionally chain pipelines. +These operators are known in PowerShell as *pipeline chain operators*, +and are similar to [AND-OR lists](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03) +in POSIX shells like bash, zsh and sh, +as well as [conditional processing symbols](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10)#using-multiple-commands-and-conditional-processing-symbols) +in Windows' command shell (cmd.exe). + +`&&` and `||` allow conditional execution of PowerShell commands and pipelines +based on the success of the left-hand pipeline. +In particular, they allow conditional execution of native executables +based on execution success: + +```powershell +npm run build && npm run deploy +``` + +The `&&` operator will execute the right-hand pipeline, +if the left-hand pipeline succeeded, +whereas the `||` operator will execute the right-hand pipeline +if the left-hand pipeline failed: + +```powershell +Write-Output 'First' && Write-Output 'Second' +``` + +```Output +First +Second +``` + +```powershell +Write-Error 'Bad' && Write-Output 'Second' +``` + +```Output +Write-Error 'Bad' && Write-Output 'Second' : Bad ++ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException ++ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException +``` + +```powershell +Write-Output 'First' || Write-Output 'Second' +``` + +```Output +First +``` + +```powershell +Write-Error 'Bad' || Write-Output 'Second' +``` + +```Output +Write-Error 'Bad' && Write-Output 'Second' : Bad ++ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException ++ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException + +Second +``` + +Pipeline success is defined by the value of the `$?` variable, +which PowerShell automatically sets after executing a pipeline based on its execution status. +This means that pipeline chain operators have the following equivalence: + +```powershell +Test-Command '1' && Test-Command '2' +``` + +works the same as + +```powershell +Test-Command '1'; if ($?) { Test-Command '2' } +``` + +and + +```powershell +Test-Command '1' || Test-Command '2' +``` + +works the same as + +```powershell +Test-Command '1'; if (-not $?) { Test-Command '2' } +``` + +### Assignment from pipeline chains + +Assigning a variable from a pipeline chain takes the concatenation +of all the pipelines in the chain: + +```powershell +$result = Write-Output '1' && Write-Output '2' +$result +``` + +```Output +1 +2 +``` + +If a script-terminating error is thrown during assignment from a pipeline chain, +the assignment does not succeed: + +```powershell +try +{ + $result = Write-Output 'Value' && $(throw 'Bad') +} +catch +{ + # Do nothing, just squash the error +} + +"Result: $result" +``` + +```Output +Result: +``` + +### Operator syntax and precedence + +Unlike other operators, `&&` and `||` operate on pipelines, +rather than on expressions (like, for example, `+` or `-and`). + +`&&` and `||` have a lower precedence than piping (`|`) or redirection (`>`), +but a higher precdence than job operators (`&`), assignment (`=`) or semicolons (`;`). +This means that pipelines within a pipeline chain can be individually redirected, +and that entire pipeline chains can be backgrounded, assigned from +or separated as statements. + +To use lower precedence syntax within a pipeline chain, +consider the use of parentheses `(...)` or a subexpression `$(...)`. + +### Error interaction + +Pipeline chain operators, particularly the `||` operator, +do not absorb errors. +If a statement in a pipeline chain throws a script-terminating error, +that will abort the pipeline chain: + +```powershell +$(throw 'Bad') || Write-Output '2' +``` + +```Output +Bad +At line:1 char:3 ++ $(throw 'Bad') || Write-Output '2' ++ ~~~~~~~~~~~ ++ CategoryInfo : OperationStopped: (Bad:String) [], RuntimeException ++ FullyQualifiedErrorId : Bad +``` + +If the error is caught, the pipeline chain will still be cut short: + +```powershell +try +{ + $(throw 'Bad') || Write-Output '2' +} +catch +{ + Write-Output "Caught: $_" +} +Write-Output 'Done' +``` + +```Output +Caught: Bad +Done +``` + +If an error is non-terminating, +or only terminates a pipeline, +the pipeline chain will continue, respecting on `$?`: + +```powershell +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' +``` + +```Output +Test-NonTerminatingError : BAD +At line:1 char:1 ++ Test-NonTerminatingError || Write-Output 'Second' ++ ~~~~~~~~~~~~~~~~~~~~~~~~ ++ CategoryInfo : NotSpecified: (:) [Test-NonTerminatingError], Exception ++ FullyQualifiedErrorId : BAD,Test-NonTerminatingError + +Second +``` + +### Chaining pipelines rather than commands + +Pipeline chain operators, by their name, can be used to chain pipelines, +rather than just commands. +This matches the behaviour of other shells, +but can make "success" harder to reason about: + +```powershell +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!' +``` + +```Output +1 +Test-NotTwo : Input is 2 +At line:1 char:9 ++ 1,2,3 | Test-NotTwo && Write-Output 'All done!' ++ ~~~~~~~~~~~ ++ CategoryInfo : InvalidData: (:) [Test-NotTwo], Exception ++ FullyQualifiedErrorId : InputTwo,Test-NotTwo + +3 +``` + +Note that `Write-Output 'All done!'` is not executed, +since `Test-NotTwo` is deemed to have failed +after throwing the non-terminating error. + +## See also + +- [about_Operators](./about_Operators.md) +- [about_Automatic_Variables](./about_Automatic_Variables.md) +- [about_pipelines](./about_pipelines.md) From 9e5c5eebede306b958362361d7fef21a3ecee41d Mon Sep 17 00:00:00 2001 From: Rob Holt Date: Mon, 30 Sep 2019 15:22:54 -0700 Subject: [PATCH 2/8] Improve see also links --- .../7/Microsoft.PowerShell.Core/About/about_Operators.md | 2 ++ .../About/about_Pipeline_Chain_Operators.md | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md index 3fa0740ad2b9..fab59514f803 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md @@ -482,6 +482,8 @@ For more information, see [about_If](about_If.md). [about_Type_Operators](about_Type_Operators.md) +[about_Pipeline_Chain_Operators](about_Pipeline_Chain_Operators.md) + [about_Split](about_Split.md) [about_Join](about_Join.md) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index 339ce6223bba..d60263158be4 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -276,6 +276,6 @@ after throwing the non-terminating error. ## See also -- [about_Operators](./about_Operators.md) -- [about_Automatic_Variables](./about_Automatic_Variables.md) -- [about_pipelines](./about_pipelines.md) +- [about_Operators](about_Operators.md) +- [about_Automatic_Variables](about_Automatic_Variables.md) +- [about_pipelines](about_pipelines.md) From e0e8d99dc5a4e5054154b3c6828c8bc83886ea67 Mon Sep 17 00:00:00 2001 From: Rob Holt Date: Mon, 30 Sep 2019 15:55:23 -0700 Subject: [PATCH 3/8] Add titles for clarity --- .../About/about_Pipeline_Chain_Operators.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index d60263158be4..6a513929aac7 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -34,7 +34,9 @@ npm run build && npm run deploy The `&&` operator will execute the right-hand pipeline, if the left-hand pipeline succeeded, whereas the `||` operator will execute the right-hand pipeline -if the left-hand pipeline failed: +if the left-hand pipeline failed. + +#### Two successful commands ```powershell Write-Output 'First' && Write-Output 'Second' @@ -45,6 +47,8 @@ First Second ``` +#### First command fails, causing second not to be executed + ```powershell Write-Error 'Bad' && Write-Output 'Second' ``` @@ -55,6 +59,8 @@ Write-Error 'Bad' && Write-Output 'Second' : Bad + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException ``` +#### First command succeeds, so `||` means second command not executed + ```powershell Write-Output 'First' || Write-Output 'Second' ``` @@ -63,6 +69,8 @@ Write-Output 'First' || Write-Output 'Second' First ``` +#### First command fails, so `||` means second command is executed + ```powershell Write-Error 'Bad' || Write-Output 'Second' ``` From 9e43a448bb76ea44404c29543c7be0c386517fa9 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Mon, 30 Sep 2019 16:18:28 -0700 Subject: [PATCH 4/8] Edit for style, etc. --- .../About/about_Operators.md | 85 ++++++++-------- .../About/about_Pipeline_Chain_Operators.md | 96 ++++++++++--------- 2 files changed, 93 insertions(+), 88 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md index fab59514f803..845580ee5d02 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Operators.md @@ -12,21 +12,20 @@ Describes the operators that are supported by PowerShell. ## Long description -An operator is a language element that you can use in a command or -expression. PowerShell supports several types of operators to help you -manipulate values. +An operator is a language element that you can use in a command or expression. +PowerShell supports several types of operators to help you manipulate values. ### Arithmetic Operators Use arithmetic operators (`+`, `-`, `*`, `/`, `%`) to calculate values in a -command or expression. With these operators, you can add, subtract, -multiply, or divide values, and calculate the remainder (modulus) of a -division operation. +command or expression. With these operators, you can add, subtract, multiply, +or divide values, and calculate the remainder (modulus) of a division +operation. The addition operator concatenates elements. The multiplication operator -returns the specified number of copies of each element. You can use -arithmetic operators on any .NET type that implements them, such as: `Int`, -`String`, `DateTime`, `Hashtable`, and Arrays. +returns the specified number of copies of each element. You can use arithmetic +operators on any .NET type that implements them, such as: `Int`, `String`, +`DateTime`, `Hashtable`, and Arrays. For more information, see [about_Arithmetic_Operators](about_Arithmetic_Operators.md). @@ -40,9 +39,9 @@ For more information, see [about_Assignment_Operators](about_Assignment_Operator ### Comparison Operators -Use comparison operators (`-eq`, `-ne`, `-gt`, `-lt`, `-le`, `-ge`) to -compare values and test conditions. For example, you can compare two string -values to determine whether they are equal. +Use comparison operators (`-eq`, `-ne`, `-gt`, `-lt`, `-le`, `-ge`) to compare +values and test conditions. For example, you can compare two string values to +determine whether they are equal. The comparison operators also include operators that find or replace patterns in text. The (`-match`, `-notmatch`, `-replace`) operators use regular @@ -51,17 +50,17 @@ expressions, and (`-like`, `-notlike`) use wildcards `*`. Containment comparison operators determine whether a test value appears in a reference set (`-in`, `-notin`, `-contains`, `-notcontains`). -Bitwise comparison operators (`-bAND`, `-bOR`, `-bXOR`, `-bNOT`) manipulate -the bit patterns in values. +Bitwise comparison operators (`-bAND`, `-bOR`, `-bXOR`, `-bNOT`) manipulate the +bit patterns in values. For more information, see [about_Comparison_Operators](about_Comparison_Operators.md). ### Logical Operators Use logical operators (`-and`, `-or`, `-xor`, `-not`, `!`) to connect -conditional statements into a single complex conditional. For example, you -can use a logical `-and` operator to create an object filter with two -different conditions. +conditional statements into a single complex conditional. For example, you can +use a logical `-and` operator to create an object filter with two different +conditions. For more information, see [about_Logical_Operators](about_logical_operators.md). @@ -77,9 +76,9 @@ For more information, see [about_Redirection](about_Redirection.md) ### Split and Join Operators -The `-split` and `-join` operators divide and combine substrings. The -`-split` operator splits a string into substrings. The `-join` operator -concatenates multiple strings into a single string. +The `-split` and `-join` operators divide and combine substrings. The `-split` +operator splits a string into substrings. The `-join` operator concatenates +multiple strings into a single string. For more information, see [about_Split](about_Split.md) and [about_Join](about_Join.md). @@ -93,15 +92,15 @@ For more information, see [about_Type_Operators](about_Type_Operators.md). ### Unary Operators -Use unary operators to increment or decrement variables or object -properties and to set integers to positive or negative numbers. For -example, to increment the variable `$a` from `9` to `10`, you type `$a++`. +Use unary operators to increment or decrement variables or object properties +and to set integers to positive or negative numbers. For example, to increment +the variable `$a` from `9` to `10`, you type `$a++`. ### Special Operators Special operators have specific use-cases that do not fit into any other -operator group. For example, special operators allow you to -run commands, change a value's data type, or retrieve elements from an array. +operator group. For example, special operators allow you to run commands, +change a value's data type, or retrieve elements from an array. #### Array subexpression operator `@( )` @@ -261,8 +260,8 @@ $job = Start-Job -ScriptBlock {Get-Process -Name pwsh} Receive-Job $job -Wait ``` -If you want to run multiple commands, each in their own background process -but all on one line, simply place `&` between and after each of the commands. +If you want to run multiple commands, each in their own background process but +all on one line, simply place `&` between and after each of the commands. For more information on PowerShell jobs, see [about_Jobs](about_Jobs.md). @@ -300,8 +299,8 @@ variables that the script creates are added to the current scope. > distinguish the dot from the dot (`.`) symbol that represents the current > directory. -In the following example, the Sample.ps1 script in the current directory is -run in the current scope. +In the following example, the Sample.ps1 script in the current directory is run +in the current scope. ```powershell . .\sample.ps1 @@ -309,9 +308,9 @@ run in the current scope. #### Format operator `-f` -Formats strings by using the format method of string objects. Enter the -format string on the left side of the operator and the objects to be -formatted on the right side of the operator. +Formats strings by using the format method of string objects. Enter the format +string on the left side of the operator and the objects to be formatted on the +right side of the operator. ```powershell "{0} {1,-10} {2:N}" -f 1,"hello",[math]::pi @@ -326,10 +325,10 @@ method and [Composite Formatting](/dotnet/standard/base-types/composite-formatti #### Index operator `[ ]` -Selects objects from indexed collections, such as arrays and hash tables. -Array indexes are zero-based, so the first object is indexed as `[0]`. For -arrays (only), you can also use negative indexes to get the last values. -Hash tables are indexed by key value. +Selects objects from indexed collections, such as arrays and hash tables. Array +indexes are zero-based, so the first object is indexed as `[0]`. For arrays +(only), you can also use negative indexes to get the last values. Hash tables +are indexed by key value. ``` PS> $a = 1, 2, 3 @@ -365,9 +364,9 @@ Once upon a time... #### Pipeline operator `|` -Sends ("pipes") the output of the command that precedes it to the command -that follows it. When the output includes more than one object (a -"collection"), the pipeline operator sends the objects one at a time. +Sends ("pipes") the output of the command that precedes it to the command that +follows it. When the output includes more than one object (a "collection"), the +pipeline operator sends the objects one at a time. ```powershell Get-Process | Get-Member @@ -376,8 +375,12 @@ Get-PSSnapin | Where-Object {$_.vendor -ne "Microsoft"} #### Pipeline chain operators `&&` and `||` -Conditionally execute the right-hand side pipeline -based on the success of the left-hand side pipeline. +> [!NOTE] +> This is an experimental feature. For more information see +> [about_Experimental_Features](about_Experimental_Features.md). + +Conditionally execute the right-hand side pipeline based on the success of the +left-hand side pipeline. ```powershell # If Get-Process successfully finds a process called notepad, diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index 6a513929aac7..1ff3d45508cf 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -14,27 +14,32 @@ Describes chaining pipelines with the `&&` and `||` operators in PowerShell. ## Long description -From PowerShell 7, PowerShell implements the `&&` and `||` operators -to conditionally chain pipelines. -These operators are known in PowerShell as *pipeline chain operators*, -and are similar to [AND-OR lists](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03) -in POSIX shells like bash, zsh and sh, -as well as [conditional processing symbols](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10)#using-multiple-commands-and-conditional-processing-symbols) -in Windows' command shell (cmd.exe). - -`&&` and `||` allow conditional execution of PowerShell commands and pipelines -based on the success of the left-hand pipeline. -In particular, they allow conditional execution of native executables -based on execution success: +Beginning in PowerShell 7, PowerShell implements the `&&` and `||` operators to +conditionally chain pipelines. These operators are known in PowerShell as +*pipeline chain operators*, and are similar to +[AND-OR lists](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03) +in POSIX shells like bash, zsh and sh, as well as +[conditional processing symbols](/previous-versions/windows/it-pro/windows-xp/bb490954(v=technet.10)#using-multiple-commands-and-conditional-processing-symbols) +in the Windows Command Shell (cmd.exe). + +The `&&` operator executes the right-hand pipeline, if the left-hand pipeline +succeeded. Conversely, the `||` operator executes the right-hand pipeline if +the left-hand pipeline failed. + +This can be use for conditional execution of software deployments. For example: ```powershell npm run build && npm run deploy ``` -The `&&` operator will execute the right-hand pipeline, -if the left-hand pipeline succeeded, -whereas the `||` operator will execute the right-hand pipeline -if the left-hand pipeline failed. +In this example the `npm run deploy` command only runs if the build command +succeeds. + +> [!NOTE] +> This is an experimental feature. For more information see +> [about_Experimental_Features](about_Experimental_Features.md). + +### Examples #### Two successful commands @@ -59,7 +64,7 @@ Write-Error 'Bad' && Write-Output 'Second' : Bad + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException ``` -#### First command succeeds, so `||` means second command not executed +#### First command succeeds, so the second command is not executed ```powershell Write-Output 'First' || Write-Output 'Second' @@ -69,7 +74,7 @@ Write-Output 'First' || Write-Output 'Second' First ``` -#### First command fails, so `||` means second command is executed +#### First command fails, so the second command is executed ```powershell Write-Error 'Bad' || Write-Output 'Second' @@ -83,8 +88,8 @@ Write-Error 'Bad' && Write-Output 'Second' : Bad Second ``` -Pipeline success is defined by the value of the `$?` variable, -which PowerShell automatically sets after executing a pipeline based on its execution status. +Pipeline success is defined by the value of the `$?` variable, which PowerShell +automatically sets after executing a pipeline based on its execution status. This means that pipeline chain operators have the following equivalence: ```powershell @@ -111,8 +116,8 @@ Test-Command '1'; if (-not $?) { Test-Command '2' } ### Assignment from pipeline chains -Assigning a variable from a pipeline chain takes the concatenation -of all the pipelines in the chain: +Assigning a variable from a pipeline chain takes the concatenation of all the +pipelines in the chain: ```powershell $result = Write-Output '1' && Write-Output '2' @@ -124,8 +129,8 @@ $result 2 ``` -If a script-terminating error is thrown during assignment from a pipeline chain, -the assignment does not succeed: +If a script-terminating error is thrown during assignment from a pipeline +chain, the assignment does not succeed: ```powershell try @@ -146,24 +151,24 @@ Result: ### Operator syntax and precedence -Unlike other operators, `&&` and `||` operate on pipelines, -rather than on expressions (like, for example, `+` or `-and`). +Unlike other operators, `&&` and `||` operate on pipelines, rather than on +expressions like `+` or `-and`, for example. `&&` and `||` have a lower precedence than piping (`|`) or redirection (`>`), -but a higher precdence than job operators (`&`), assignment (`=`) or semicolons (`;`). -This means that pipelines within a pipeline chain can be individually redirected, -and that entire pipeline chains can be backgrounded, assigned from -or separated as statements. +but a higher precedence than job operators (`&`), assignment (`=`) or +semicolons (`;`). This means that pipelines within a pipeline chain can be +individually redirected, and that entire pipeline chains can be backgrounded, +assigned to variables, or separated as statements. -To use lower precedence syntax within a pipeline chain, -consider the use of parentheses `(...)` or a subexpression `$(...)`. +To use lower precedence syntax within a pipeline chain, consider the use of +parentheses `(...)` or a subexpression `$(...)`. ### Error interaction -Pipeline chain operators, particularly the `||` operator, -do not absorb errors. -If a statement in a pipeline chain throws a script-terminating error, -that will abort the pipeline chain: +Pipeline chain operators do not absorb errors. When a statement in a pipeline +chain throws a script-terminating error, the pipeline chain is terminated. + +For example: ```powershell $(throw 'Bad') || Write-Output '2' @@ -178,7 +183,7 @@ At line:1 char:3 + FullyQualifiedErrorId : Bad ``` -If the error is caught, the pipeline chain will still be cut short: +Even when the error is caught, the pipeline chain is still terminated: ```powershell try @@ -197,9 +202,8 @@ Caught: Bad Done ``` -If an error is non-terminating, -or only terminates a pipeline, -the pipeline chain will continue, respecting on `$?`: +If an error is non-terminating, or only terminates a pipeline, the pipeline +chain continues, respecting the value of `$?`: ```powershell function Test-NonTerminatingError @@ -232,10 +236,9 @@ Second ### Chaining pipelines rather than commands -Pipeline chain operators, by their name, can be used to chain pipelines, -rather than just commands. -This matches the behaviour of other shells, -but can make "success" harder to reason about: +Pipeline chain operators, by their name, can be used to chain pipelines, rather +than just commands. This matches the behavior of other shells, but can make +*success* harder to determine: ```powershell function Test-NotTwo @@ -278,9 +281,8 @@ At line:1 char:9 3 ``` -Note that `Write-Output 'All done!'` is not executed, -since `Test-NotTwo` is deemed to have failed -after throwing the non-terminating error. +Note that `Write-Output 'All done!'` is not executed, since `Test-NotTwo` is +deemed to have failed after throwing the non-terminating error. ## See also From 0a5282c1bd935d99ff85bd7a25cfcaa6f1fcf00d Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Tue, 1 Oct 2019 09:08:20 -0700 Subject: [PATCH 5/8] Review feedback --- .../About/about_Pipeline_Chain_Operators.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index 1ff3d45508cf..2b2675d69a6e 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -14,6 +14,10 @@ Describes chaining pipelines with the `&&` and `||` operators in PowerShell. ## Long description +> [!NOTE] +> This is an experimental feature. For more information see +> [about_Experimental_Features](about_Experimental_Features.md). + Beginning in PowerShell 7, PowerShell implements the `&&` and `||` operators to conditionally chain pipelines. These operators are known in PowerShell as *pipeline chain operators*, and are similar to @@ -26,7 +30,10 @@ The `&&` operator executes the right-hand pipeline, if the left-hand pipeline succeeded. Conversely, the `||` operator executes the right-hand pipeline if the left-hand pipeline failed. -This can be use for conditional execution of software deployments. For example: +These operators use the `$?` and `$LASTEXITCODE` variable to determine if a +pipeline failed. This allows you to use them with native command and not just +with cmdlets or functions. This can be use for conditional execution of +software deployments. For example: ```powershell npm run build && npm run deploy @@ -35,10 +42,6 @@ npm run build && npm run deploy In this example the `npm run deploy` command only runs if the build command succeeds. -> [!NOTE] -> This is an experimental feature. For more information see -> [about_Experimental_Features](about_Experimental_Features.md). - ### Examples #### Two successful commands From 211ba99e10c03ec43271c2bec86c1346c22b99db Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Tue, 1 Oct 2019 09:33:16 -0700 Subject: [PATCH 6/8] fix typo --- .../About/about_Pipeline_Chain_Operators.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index 2b2675d69a6e..acbdc0711384 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -30,10 +30,10 @@ The `&&` operator executes the right-hand pipeline, if the left-hand pipeline succeeded. Conversely, the `||` operator executes the right-hand pipeline if the left-hand pipeline failed. -These operators use the `$?` and `$LASTEXITCODE` variable to determine if a +These operators use the `$?` and `$LASTEXITCODE` variables to determine if a pipeline failed. This allows you to use them with native command and not just -with cmdlets or functions. This can be use for conditional execution of -software deployments. For example: +with cmdlets or functions. For example, this could be used for conditional +execution of a software deployment: ```powershell npm run build && npm run deploy From fae3c77bf7afe7552fe463aeba24e0e1f3178b90 Mon Sep 17 00:00:00 2001 From: Sean Wheeler Date: Tue, 1 Oct 2019 17:31:11 -0700 Subject: [PATCH 7/8] changed example --- .../About/about_Pipeline_Chain_Operators.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index acbdc0711384..17377c74002e 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -31,17 +31,14 @@ succeeded. Conversely, the `||` operator executes the right-hand pipeline if the left-hand pipeline failed. These operators use the `$?` and `$LASTEXITCODE` variables to determine if a -pipeline failed. This allows you to use them with native command and not just -with cmdlets or functions. For example, this could be used for conditional -execution of a software deployment: +pipeline failed. This allows you to use them with native commands and not just +with cmdlets or functions. For example: ```powershell -npm run build && npm run deploy +# 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 ``` -In this example the `npm run deploy` command only runs if the build command -succeeds. - ### Examples #### Two successful commands From 8a149269b8f37d18ec1b08cb493e500a7917199d Mon Sep 17 00:00:00 2001 From: Rob Holt Date: Thu, 3 Oct 2019 09:26:34 -0700 Subject: [PATCH 8/8] Add note about associativity --- .../About/about_Pipeline_Chain_Operators.md | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md index 17377c74002e..3ed9d02e88c1 100644 --- a/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md +++ b/reference/7/Microsoft.PowerShell.Core/About/about_Pipeline_Chain_Operators.md @@ -160,8 +160,34 @@ semicolons (`;`). This means that pipelines within a pipeline chain can be individually redirected, and that entire pipeline chains can be backgrounded, assigned to variables, or separated as statements. -To use lower precedence syntax within a pipeline chain, consider the use of -parentheses `(...)` or a subexpression `$(...)`. +To use lower precedence syntax within a pipeline chain, +consider the use of parentheses `(...)` or a subexpression `$(...)`. +Note that enclosing an expression in parentheses or a subexpression +will set `$?` to true irrespective of the expression itself, +causing a different outcome in the pipeline chain. + +Like most other operators in PowerShell, `&&` and `||` are also *left-associative*, +meaning they group from the left. For example: + +```powershell +Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist" && Get-Content -Raw ./file.txt +``` + +will group as: + +``` +[Get-ChildItem -Path ./file.txt || Write-Error "file.txt does not exist"] && Get-Content -Raw ./file.txt +``` + +being equivalent to: + +```powershell +Get-ChildItem -Path ./file.txt + +if (-not $?) { Write-Error "file.txt does not exist" } + +if ($?) { Get-Content -Raw ./file.txt } +``` ### Error interaction