Reputation: 3144
In bash, I can do this:
if this_command >/dev/null 2>&1; then
ANSWER="this_command"
elif that_command >/dev/null 2>&1; then
ANSWER="that_command"
else
ANSWER="neither command"
fi
but in Powershell, I have to do this:
this_command >/dev/null 2>&1
if ($?) {
ANSWER="this_command"
} else {
that_command >/dev/null 2>&1
if ($?) {
ANSWER="that_command"
} else {
ANSWER="neither command"
}
}
or something similar with ($LASTEXITCODE -eq 0)
. How do I make the Powershell look like bash? I'm not a Powershell expert, but I cannot believe that it doesn't not provide some means of running a command and checking its return code in a single statement in a way that could be used in an if-elseif-else statement. This statement would be increasingly difficult to read with every external command that must be tested in this way.
Upvotes: 3
Views: 880
Reputation: 440297
PowerShell's native error handling works completely differently from the exit-code-based error signaling performed by external programs, and, unfortunately, error handling with external programs in PowerShell is cumbersome, requiring explicit checks of the automatic $?
or $LASTEXITCODE
variables.
PowerShell [Core]:
introduced support for Bash-style &&
and ||
pipeline-chain operators in v7 - see this answer.
but this will not also enable use of external-program calls in if
statements, because there PowerShell will continue to operate on the output from commands, not on their implied success status / exit code; see this answer for more information.
Solutions:
PowerShell [Core] 7.0+:
$ANSWER = this_command *>$null && "this_command" ||
(that_command *>$null && "that_command" || "neither command")
Note:
If this_command
or that_command
don't exist (can't be found), a statement-terminating error occurs, i.e. the statement fails as a whole.
Note the need to enclose the 2nd chain in (...)
so that && "that_command"
doesn't also kick in when this_command
succeeds.
*>$null
is used to conveniently silence all streams with a single redirection.
Unlike an if
-based solution, this technique passes (non-suppressed) output from the external programs through.
Windows PowerShell and PowerShell Core 6.x:
If the external-program calls produce no output or you actively want to suppress their output, as in your question:
$(...)
-based technique in Ansgar Wiechers' helpful answer.If you do want the external programs' output:
An aux. dummy do
loop allows for a fairly "low-noise" solution:
$ANSWER = do {
this_command # Note: No output suppression
if ($?) { "this_command"; break }
that_command # Note: No output suppression
if ($?) { "that_command"; break }
"neither command"
} while ($false)
Upvotes: 1
Reputation: 200503
For PowerShell cmdlets you can do the exact same thing you do in bash. You don't even need to do individual assignments in each branch. Just output what you want to assign and collect the output of the entire conditional in a variable.
$ANSWER = if (Do-Something >$null 2>&1) {
'this_command'
} elseif (Do-Other >$null 2>&1) {
'that_command'
} else {
'neither command'
}
For external commands it's slightly different, because PowerShell would evaluate the command output, not the exit code/status (with empty output evaluating to "false"). But you can run the command in a subexpression and output the status to get the desired result.
$ANSWER = if ($(this_command >$null 2>&1; $?)) {
'this_command'
} elseif ($(that_command >$null 2>&1; $?)) {
'that_command'
} else {
'neither command'
}
Note that you must use a subexpression ($(...)
), not a grouping expression ((...)
), because you effectively need to run 2 commands in a row (run external command, then output status), which the latter doesn't support.
Upvotes: 5
Reputation: 27606
Another approach is to have it output an empty string if it's false:
if (echo hi | findstr there) { 'yes' }
if (echo hi | findstr hi) { 'yes' }
yes
Upvotes: 1
Reputation: 21488
You can't do it inline like in bash
, but you can one-line this with two statements on one line, separated by a semi-colon ;
:
MyProgram.exe -param1 -param2 -etc *>$null; if( $LASTEXITCODE -eq 0 ) {
# Success code here
} else {
# Fail code here
}
Also, you can't use $?
with commands, only Powershell cmdlets, which is why we check that $LASTEXITCODE -eq 0
instead of using $?
.
Note that you CAN evaluate cmdlets inline, just not external commands. For example:
if( Test-Connection stackoverflow.com ){
"success"
} else {
"fail"
}
Upvotes: 1