Skip to content

Commit bdccbbe

Browse files
author
Sean Wheeler
committed
Merge branch 'pipeline-chain-operators' of https://github.com/rjmholt/PowerShell-Docs into pipeline-chain-operators
2 parents 2bbe7c4 + 741e1af commit bdccbbe

File tree

2 files changed

+299
-0
lines changed

2 files changed

+299
-0
lines changed

reference/7/Microsoft.PowerShell.Core/About/about_Operators.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,22 @@ Get-Process | Get-Member
374374
Get-PSSnapin | Where-Object {$_.vendor -ne "Microsoft"}
375375
```
376376

377+
#### Pipeline chain operators `&&` and `||`
378+
379+
Conditionally execute the right-hand side pipeline
380+
based on the success of the left-hand side pipeline.
381+
382+
```powershell
383+
# If Get-Process successfully finds a process called notepad,
384+
# Stop-Process -Name notepad is called
385+
Get-Process notepad && Stop-Process -Name notepad
386+
```
387+
388+
```powershell
389+
# If npm install fails, the node_modules directory is removed
390+
npm install || Remove-Item -Recurse ./node_modules
391+
```
392+
377393
#### Property dereferences operator `.`
378394

379395
Accesses the properties and methods of an object.
@@ -466,6 +482,8 @@ For more information, see [about_If](about_If.md).
466482

467483
[about_Type_Operators](about_Type_Operators.md)
468484

485+
[about_Pipeline_Chain_Operators](about_Pipeline_Chain_Operators.md)
486+
469487
[about_Split](about_Split.md)
470488

471489
[about_Join](about_Join.md)
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
---
2+
ms.date: 09/30/2019
3+
schema: 2.0.0
4+
locale: en-us
5+
keywords: powershell,cmdlet
6+
title: about_Pipeline_Chain_Operators
7+
---
8+
9+
# About Pipeline Chain Operators
10+
11+
## Short description
12+
13+
Describes chaining pipelines with the `&&` and `||` operators in PowerShell.
14+
15+
## Long description
16+
17+
From PowerShell 7, PowerShell implements the `&&` and `||` operators
18+
to conditionally chain pipelines.
19+
These operators are known in PowerShell as *pipeline chain operators*,
20+
and are similar to [AND-OR lists](https://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_03)
21+
in POSIX shells like bash, zsh and sh,
22+
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)
23+
in Windows' command shell (cmd.exe).
24+
25+
`&&` and `||` allow conditional execution of PowerShell commands and pipelines
26+
based on the success of the left-hand pipeline.
27+
In particular, they allow conditional execution of native executables
28+
based on execution success:
29+
30+
```powershell
31+
npm run build && npm run deploy
32+
```
33+
34+
The `&&` operator will execute the right-hand pipeline,
35+
if the left-hand pipeline succeeded,
36+
whereas the `||` operator will execute the right-hand pipeline
37+
if the left-hand pipeline failed:
38+
39+
```powershell
40+
Write-Output 'First' && Write-Output 'Second'
41+
```
42+
43+
```Output
44+
First
45+
Second
46+
```
47+
48+
```powershell
49+
Write-Error 'Bad' && Write-Output 'Second'
50+
```
51+
52+
```Output
53+
Write-Error 'Bad' && Write-Output 'Second' : Bad
54+
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
55+
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
56+
```
57+
58+
```powershell
59+
Write-Output 'First' || Write-Output 'Second'
60+
```
61+
62+
```Output
63+
First
64+
```
65+
66+
```powershell
67+
Write-Error 'Bad' || Write-Output 'Second'
68+
```
69+
70+
```Output
71+
Write-Error 'Bad' && Write-Output 'Second' : Bad
72+
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
73+
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
74+
75+
Second
76+
```
77+
78+
Pipeline success is defined by the value of the `$?` variable,
79+
which PowerShell automatically sets after executing a pipeline based on its execution status.
80+
This means that pipeline chain operators have the following equivalence:
81+
82+
```powershell
83+
Test-Command '1' && Test-Command '2'
84+
```
85+
86+
works the same as
87+
88+
```powershell
89+
Test-Command '1'; if ($?) { Test-Command '2' }
90+
```
91+
92+
and
93+
94+
```powershell
95+
Test-Command '1' || Test-Command '2'
96+
```
97+
98+
works the same as
99+
100+
```powershell
101+
Test-Command '1'; if (-not $?) { Test-Command '2' }
102+
```
103+
104+
### Assignment from pipeline chains
105+
106+
Assigning a variable from a pipeline chain takes the concatenation
107+
of all the pipelines in the chain:
108+
109+
```powershell
110+
$result = Write-Output '1' && Write-Output '2'
111+
$result
112+
```
113+
114+
```Output
115+
1
116+
2
117+
```
118+
119+
If a script-terminating error is thrown during assignment from a pipeline chain,
120+
the assignment does not succeed:
121+
122+
```powershell
123+
try
124+
{
125+
$result = Write-Output 'Value' && $(throw 'Bad')
126+
}
127+
catch
128+
{
129+
# Do nothing, just squash the error
130+
}
131+
132+
"Result: $result"
133+
```
134+
135+
```Output
136+
Result:
137+
```
138+
139+
### Operator syntax and precedence
140+
141+
Unlike other operators, `&&` and `||` operate on pipelines,
142+
rather than on expressions (like, for example, `+` or `-and`).
143+
144+
`&&` and `||` have a lower precedence than piping (`|`) or redirection (`>`),
145+
but a higher precdence than job operators (`&`), assignment (`=`) or semicolons (`;`).
146+
This means that pipelines within a pipeline chain can be individually redirected,
147+
and that entire pipeline chains can be backgrounded, assigned from
148+
or separated as statements.
149+
150+
To use lower precedence syntax within a pipeline chain,
151+
consider the use of parentheses `(...)` or a subexpression `$(...)`.
152+
153+
### Error interaction
154+
155+
Pipeline chain operators, particularly the `||` operator,
156+
do not absorb errors.
157+
If a statement in a pipeline chain throws a script-terminating error,
158+
that will abort the pipeline chain:
159+
160+
```powershell
161+
$(throw 'Bad') || Write-Output '2'
162+
```
163+
164+
```Output
165+
Bad
166+
At line:1 char:3
167+
+ $(throw 'Bad') || Write-Output '2'
168+
+ ~~~~~~~~~~~
169+
+ CategoryInfo : OperationStopped: (Bad:String) [], RuntimeException
170+
+ FullyQualifiedErrorId : Bad
171+
```
172+
173+
If the error is caught, the pipeline chain will still be cut short:
174+
175+
```powershell
176+
try
177+
{
178+
$(throw 'Bad') || Write-Output '2'
179+
}
180+
catch
181+
{
182+
Write-Output "Caught: $_"
183+
}
184+
Write-Output 'Done'
185+
```
186+
187+
```Output
188+
Caught: Bad
189+
Done
190+
```
191+
192+
If an error is non-terminating,
193+
or only terminates a pipeline,
194+
the pipeline chain will continue, respecting on `$?`:
195+
196+
```powershell
197+
function Test-NonTerminatingError
198+
{
199+
[CmdletBinding()]
200+
param()
201+
202+
$exception = [System.Exception]::new('BAD')
203+
$errorId = 'BAD'
204+
$errorCategory = 'NotSpecified'
205+
206+
$errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, $errorId, $errorCategory, $null)
207+
208+
$PSCmdlet.WriteError($errorRecord)
209+
}
210+
211+
Test-NonTerminatingError || Write-Output 'Second'
212+
```
213+
214+
```Output
215+
Test-NonTerminatingError : BAD
216+
At line:1 char:1
217+
+ Test-NonTerminatingError || Write-Output 'Second'
218+
+ ~~~~~~~~~~~~~~~~~~~~~~~~
219+
+ CategoryInfo : NotSpecified: (:) [Test-NonTerminatingError], Exception
220+
+ FullyQualifiedErrorId : BAD,Test-NonTerminatingError
221+
222+
Second
223+
```
224+
225+
### Chaining pipelines rather than commands
226+
227+
Pipeline chain operators, by their name, can be used to chain pipelines,
228+
rather than just commands.
229+
This matches the behaviour of other shells,
230+
but can make "success" harder to reason about:
231+
232+
```powershell
233+
function Test-NotTwo
234+
{
235+
[CmdletBinding()]
236+
param(
237+
[Parameter(ValueFromPipeline)]
238+
$Input
239+
)
240+
241+
process
242+
{
243+
if ($Input -ne 2)
244+
{
245+
return $Input
246+
}
247+
248+
$exception = [System.Exception]::new('Input is 2')
249+
$errorId = 'InputTwo'
250+
$errorCategory = 'InvalidData'
251+
252+
$errorRecord = [System.Management.Automation.ErrorRecord]::new($exception, $errorId, $errorCategory, $null)
253+
254+
$PSCmdlet.WriteError($errorRecord)
255+
}
256+
}
257+
258+
1,2,3 | Test-NotTwo && Write-Output 'All done!'
259+
```
260+
261+
```Output
262+
1
263+
Test-NotTwo : Input is 2
264+
At line:1 char:9
265+
+ 1,2,3 | Test-NotTwo && Write-Output 'All done!'
266+
+ ~~~~~~~~~~~
267+
+ CategoryInfo : InvalidData: (:) [Test-NotTwo], Exception
268+
+ FullyQualifiedErrorId : InputTwo,Test-NotTwo
269+
270+
3
271+
```
272+
273+
Note that `Write-Output 'All done!'` is not executed,
274+
since `Test-NotTwo` is deemed to have failed
275+
after throwing the non-terminating error.
276+
277+
## See also
278+
279+
- [about_Operators](about_Operators.md)
280+
- [about_Automatic_Variables](about_Automatic_Variables.md)
281+
- [about_pipelines](about_pipelines.md)

0 commit comments

Comments
 (0)