You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure - short-circuiting Boolean execution-flow control operators #3241
Bash-style && and || control operators would be handy additions to the language.
For instance, instead of writing (the examples are contrived, but hopefully illustrate the point):
# If command A succeeds, execute command B too.
csc /nologo file.cs
if (0-eq$LASTEXITCODE) { git commit -m 'ok' }
# if command A fails, execute command B.
csc /nologo file.cs
if (0-ne$LASTEXITCODE) { git commit -m 'failed' }
one might be able to write:
# If command A succeeds, execute command B too.
csc /nologo file.cs && git commit -m 'ok'# if command A fails, execute command B.
csc /nologo file.cs || git commit -m 'failed'
The examples use external utilities, but these operators would be equally handy for PowerShell-native commands (where $? rather than $LASTEXITCODE would have to be examined).
changed the title [-]Suggestion: implement Bash-style && and || control operators[/-][+]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure[/+]on Aug 14, 2017
changed the title [-]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure[/-][+]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure - short-circuiting Boolean execution-flow control operators[/+]on Oct 3, 2017
Short circuit operators are such a fundamental part of the daily shell use at the command line and it is a massive burden to work without them. And the -and/-or operators are not a replacement since they simply output the boolean result of the operation making them useless for interactive use.
Reacted by Michael Klement, Ivan171, Chris Harbert, Bo Lingen, Xavier Poinas, ExE Boss, maffe, Luke Schlather, Tom Alon and Raffaello
Svend Tofte (@stofte): PowerShell has 2 personalities (fundamental syntax forms): argument mode (like a shell) and expression mode (like a programming language) - see Get-Help about_Parsing.
-and and -or belong to the expression-mode world and operate on (often inferred) Boolean values.
They have no equivalent in argument mode, and that's the crux of the problem.
Your example, Foo -and $False is parsed in argument mode, because the statement's first token is a command. Therefore, you're passing tokens -and and -$False as arguments (parameter values) to function Foo - where, in your case, they're ignored and the output is simply $True.
If you want to use a command (argument mode) as part of an expression (expression mode; e.g., with -and), you must enclose it in parentheses:
return (Foo) -and $False
Reacted by Keith Hill, Peter Atashian, Mariusz Pawelski, David Rodrigue, Kagami Sascha Rosylight, Brian G. Shacklett, Svend Tofte, Felix Freiberger, ExE Boss, Ajay Mehta and 3 more
Michael Klement (@mklement0) Thanks for the explanation. It's still not entirely clear how argument modes relates and interacts with outcome vs output parsing/interpretation however.
PS is probably the most confusing language I've come across in my years. It seems to assemble a hodge-podge of ideas in order to be everything for everyone (anyway, ranting over!)
Svend Tofte (@stofte) You pass parameters to functions via the - character so any - characters after the function are going to be assumed to be parameters. So Foo -and $false is really trying to pass -and as the parameter name with $false as the value but since Foo doesn't define any parameters, it just ignores it.
Let's change your script a bit to add parameters and see how it works.
Now, Foo will accept the parameter and pass $false into the function. However, it still returns $true since that is what the function outputs.
So for PowerShell to know if it shouldn't be trying to pass -and as a parameter, you need to use parenthesis to control order of operations. (Foo) -and $false now will run Foo first, then evaluate the remaining statement $true -and -$false.
BTW, PowerShell ISE and Visual Studio Code is smart enough to tell you all of this via Intellisense. It knows that the -and operator can't be used in your original code and won't give it as an option. I highly recommend using Intellisense to make sure keywords are usable in the right context.
Now for why functions are using - to pass parameters is because the idea behind PowerShell is to create command-line applications through functions instead of having to compile an application. So a Function mimics much of the command-line experience to make it happen.
Reacted by Svend Tofte, Brian G. Shacklett and Subrat
A thought I have is that if && and || only look at $LASTEXITCODE it makes them pretty specific -- two new operators that only work in the context of native commands. And without good knowledge of that fact, something like
csc.exe program.cs
Foo && Bar
could prove very confusing, since it either uses the $LASTEXITCODE value, in which case Bar being executed depends on the success of the csc.exe line. OR, if just assumes that a non-native command succeeds (or whatever) that is just as confusing. OR, we throw an error because Foo isn't a native command...
Specifically, Foo && Bar evaluates Foo and if the result coerces to $false, it returns that (pre-coercion) value, otherwise it returns the result of Bar. With Foo || Bar, Foo is evaluated and if the result coerces to $true it returns that (pre-coercion) result, otherwise we evaluate and return the result of Bar. The operators would have equal precedence and be left-associative, so you can chain them like so:
>"" || "Hello" && "Goodbye"
Goodbye
That last thing is pretty confusing, but would be useful for chains of only one operator (Step1 && Step2 && Step3, Try1 || Failover1 || Failover2) and I see no particular reason not to support a mixed chain.
Notice that this also gives us a null-coalescing functionality like so: $x = $v || "default". With a mixed chain you'd even get a (rather confusing) ternary operator: $condition && $ifTrue || $ifFalse.
However, the problem is that this wouldn't scratch the itch of wanting a way to chain native commands. So, we could make it that when one of these operators evaluates a native command as an argument, it proceeds based on the $LASTEXITCODE value, so that the following work:
>csc.exe badprogram.cs && RunProgram
# error output from csc.exe, RunProgram not evaluated> SetupProject && csc.exe goodprogram.cs
# output from csc.exe, SetupProject evaluated
I think that's a bit complex, but unfortunately it seems to be most sensible and useful option I can see.
Anyway, please let me know your thoughts on this -- I'm just spitballing ideas here (although I'm always in favour of consistency). After some initial thoughts/comments here, I'd like to write up an RFC with a more concrete proposal and then implement a prototype.
So I was thinking about something more like JavaScript's (please, hear me out...) short circuit operator implementation
I still think we need to use $LASTEXITCODE. For example, think about npm run build && npm run deploy. npm run build can emit some text even when it fails, and I want to prevent npm run deploy from running after a failed build.
Vladimir Yakovlev (@vladimiry) Thanks, but this issue is about a concise, success-conditional idiom for sequencing commands; by contrast, your link is (primarily) about unconditional parallel execution via PowerShell workflows, which aren't supported in PowerShell Core.
Reacted by Steve Lee, Rain Sallow (/u/ta11ow), Paul Reichelt-Ritter, ExE Boss, Ivan171, PRASOON KARUNAN V, gwttk, Raphael, Marvin Davieds, xa0082249956 and 4 more
Raffaello (@Raffaello) If you checked the PR that closed this you'd have seen it was added in for 7.0.0-preview5 - so it is in Powershell since the GA of v7.0.0
Activity
[-]Suggestion: implement Bash-style && and || control operators[/-][+]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure[/+]i-give-up commentedon Oct 3, 2017
I believe the proper term for
&&and||is "short-circuit operator".[-]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure[/-][+]Suggestion: implement Bash-style && and || control operators for chaining commands based on success / failure - short-circuiting Boolean execution-flow control operators[/+]mklement0 commentedon Oct 3, 2017
i-give-up: While short-circuiting is an important aspect of these operators' behavior, both Bash and POSIX call them control operators.
If you wanted to get as descriptive as possible, I guess you could call them short-circuiting Boolean execution-flow control operators.
So as to make this issue more easily discoverable, I've appended that term to the issue's title.
lenkite commentedon Oct 18, 2017
Short circuit operators are such a fundamental part of the daily shell use at the command line and it is a massive burden to work without them. And the
-and/-oroperators are not a replacement since they simply output the boolean result of the operation making them useless for interactive use.stofte commentedon Nov 9, 2017
I dont understand what the -and operator actually does (and presumably the -or as well).
It's simply baffling to have the following code and see "True" come out when you run it
The OPs stackoverflow really shows everything that is fubared about this design.
mklement0 commentedon Nov 9, 2017
Svend Tofte (@stofte): PowerShell has 2 personalities (fundamental syntax forms): argument mode (like a shell) and expression mode (like a programming language) - see
Get-Help about_Parsing.-andand-orbelong to the expression-mode world and operate on (often inferred) Boolean values.They have no equivalent in argument mode, and that's the crux of the problem.
Your example,
Foo -and $Falseis parsed in argument mode, because the statement's first token is a command. Therefore, you're passing tokens-andand-$Falseas arguments (parameter values) to functionFoo- where, in your case, they're ignored and the output is simply$True.If you want to use a command (argument mode) as part of an expression (expression mode; e.g., with
-and), you must enclose it in parentheses:stofte commentedon Nov 10, 2017
Michael Klement (@mklement0) Thanks for the explanation. It's still not entirely clear how argument modes relates and interacts with outcome vs output parsing/interpretation however.
PS is probably the most confusing language I've come across in my years. It seems to assemble a hodge-podge of ideas in order to be everything for everyone (anyway, ranting over!)
dragonwolf83 commentedon Nov 10, 2017
Svend Tofte (@stofte) You pass parameters to functions via the
-character so any-characters after the function are going to be assumed to be parameters. SoFoo -and $falseis really trying to pass-andas the parameter name with$falseas the value but sinceFoodoesn't define any parameters, it just ignores it.Let's change your script a bit to add parameters and see how it works.
Now,
Foowill accept the parameter and pass$falseinto the function. However, it still returns$truesince that is what the function outputs.So for PowerShell to know if it shouldn't be trying to pass
-andas a parameter, you need to use parenthesis to control order of operations.(Foo) -and $falsenow will runFoofirst, then evaluate the remaining statement$true -and -$false.BTW, PowerShell ISE and Visual Studio Code is smart enough to tell you all of this via Intellisense. It knows that the
-andoperator can't be used in your original code and won't give it as an option. I highly recommend using Intellisense to make sure keywords are usable in the right context.Now for why functions are using
-to pass parameters is because the idea behind PowerShell is to create command-line applications through functions instead of having to compile an application. So a Function mimics much of the command-line experience to make it happen.jurriaanr commentedon Apr 13, 2018
I can't believe I still have to start up cmd for this functionality, my bash using colleagues are making fun of me
rjmholt commentedon Apr 21, 2018
I've been thinking about this a bit.
A thought I have is that if
&&and||only look at$LASTEXITCODEit makes them pretty specific -- two new operators that only work in the context of native commands. And without good knowledge of that fact, something likecsc.exe program.cs Foo && Barcould prove very confusing, since it either uses the
$LASTEXITCODEvalue, in which caseBarbeing executed depends on the success of thecsc.exeline. OR, if just assumes that a non-native command succeeds (or whatever) that is just as confusing. OR, we throw an error becauseFooisn't a native command...So I was thinking about something more like JavaScript's (please, hear me out...) short circuit operator implementation. That way you could do:
Specifically,
Foo && BarevaluatesFooand if the result coerces to$false, it returns that (pre-coercion) value, otherwise it returns the result ofBar. WithFoo || Bar,Foois evaluated and if the result coerces to$trueit returns that (pre-coercion) result, otherwise we evaluate and return the result ofBar. The operators would have equal precedence and be left-associative, so you can chain them like so:That last thing is pretty confusing, but would be useful for chains of only one operator (
Step1 && Step2 && Step3,Try1 || Failover1 || Failover2) and I see no particular reason not to support a mixed chain.Notice that this also gives us a null-coalescing functionality like so:
$x = $v || "default". With a mixed chain you'd even get a (rather confusing) ternary operator:$condition && $ifTrue || $ifFalse.However, the problem is that this wouldn't scratch the itch of wanting a way to chain native commands. So, we could make it that when one of these operators evaluates a native command as an argument, it proceeds based on the
$LASTEXITCODEvalue, so that the following work:I think that's a bit complex, but unfortunately it seems to be most sensible and useful option I can see.
Anyway, please let me know your thoughts on this -- I'm just spitballing ideas here (although I'm always in favour of consistency). After some initial thoughts/comments here, I'd like to write up an RFC with a more concrete proposal and then implement a prototype.
saschanaz commentedon Apr 21, 2018
I still think we need to use $LASTEXITCODE. For example, think about
npm run build && npm run deploy.npm run buildcan emit some text even when it fails, and I want to preventnpm run deployfrom running after a failed build.22 remaining items
mikemaccana commentedon Apr 6, 2019
Steve Lee (@SteveL-MSFT) Since there won't be a 6.3 - consider it for 7?
SteveL-MSFT commentedon Apr 7, 2019
Mike MacCana (@mikemaccana) I've renamed the 6.3-Consider milestone to 7.0-Consider
vladimiry commentedon Apr 27, 2019
Seems to be related information https://community.dynamics.com/nav/b/stefanodemiliani/archive/2018/02/28/running-microsoft-dynamics-nav-tasks-in-parallel-with-powershell (parallel / sequential commands execution).
mklement0 commentedon Apr 27, 2019
Vladimir Yakovlev (@vladimiry) Thanks, but this issue is about a concise, success-conditional idiom for sequencing commands; by contrast, your link is (primarily) about unconditional parallel execution via PowerShell workflows, which aren't supported in PowerShell Core.
rjmholt commentedon Jun 12, 2019
Please see PowerShell/PowerShell-RFC#192
Try to work around powershell being the stupidest shell ever
Raffaello commentedon Jan 15, 2022
in powershell ver 5.1 are still not present, which version of Powershell include these operators?
kilasuit commentedon Jan 15, 2022
Raffaello (@Raffaello) If you checked the PR that closed this you'd have seen it was added in for 7.0.0-preview5 - so it is in Powershell since the GA of v7.0.0