In Bash I can easily do something like
command1 && command2 || command3
which means to run command1 and if command1 succeeds to run
Update: &&
and ||
have finally come to PowerShell (Core), namely in v7; see this answer.
Many years after the question was first asked, let me summarize the state of affairs as of PowerShell v5.1:
Bash's / cmd
's &&
and ||
control operators have NO PowerShell equivalents, and since you cannot define custom operators in PowerShell, there are no good workarounds:
Use separate commands (on separate lines or separated with ;
), and explicitly test the success status of each command via automatic variable $?
, such as:
command1 -arg1 -arg2; if ($?) { command2 -arg1 } # equivalent of &&
command1 -arg1 -arg2; if (-not $?) { command2 -arg1 } # equivalent of ||
See below for why PowerShell's -and
and -or
are generally not a solution.
There was talk about adding them a while back, but it seemingly never made the top of the list.
&&
and ||
are currently reserved for future use in PowerShell, so there's hope that the same syntax as in Bash can be implemented.1 && 1
yields error message The token '&&' is not a valid statement separator in this version.
)-and
and -or
are no substitute for &&
and ||
:Bash's control operators &&
(short-circuiting logical AND) and ||
(short-circuiting logical OR) implicitly check the success status of commands by their exit codes, without interfering with their output streams; e.g.:
ls / nosuchfile && echo 'ok'
Whatever ls
outputs -- both stdout output (the files in /
) and stderr output (the error message from attempting to access non-existent file nosuchfile
) -- is passed through, but &&
checks the (invisible) exit code of the ls
command to decide if the echo
command - the RHS of the &&
control operator - should be executed.
ls
reports exit code 1
in this case, signaling failure -- because file nosuchfile
doesn't exist -- so &&
decides that ls
failed and, by applying short-circuiting, decides that the echo
command need not be executed.
Note that it is exit code 0
that signals success in the world of cmd.exe
and bash
, whereas any nonzero exit code indicates failure.
In other words: Bash's &&
and ||
operate completely independently of the commands' output and only act on the success status of the commands.
PowerShell's -and
and -or
, by contrast, act only on the commands' standard (success) output, consume it and then output only the Boolean result of the operation; e.g.:
(Get-ChildItem \, nosuchfile) -and 'ok'
The above:
uses and consumes the success (standard) output -- the listing of \
-- and interprets it as a Boolean; a non-empty input collection is considered $true
in a Boolean context, so if there's at least one entry, the expression evaluates to $true
.
nosuchfile
is passed through, because errors are sent to a separate stream.Given that Get-ChildItem \, nosuchfile
returns non-empty success output, the LHS evaluated to $true
, so -and
also evaluates the RHS, 'ok'
, but, again, consumes its output and interprets it as a Boolean, which, as a nonempty string, also evaluates to $true
.
Thus, the overall result of the -and
expression is $true
, which is (the only success) output.
The net effect is:
The success output from both sides of the -and
expression is consumed during evaluation and therefore effectively hidden.
The expression's only (success) output is its Boolean result, which is $true
in this case (which renders as True
in the terminal in English-language systems).
We can use try catch finally method instead of using && method in powershell.
try {hostname} catch {echo err} finally {ipconfig /all | findstr bios}
You can do something like this, where you hide the boolean output with [void], and only get the side effect. In this case, if $a or $b are null, then $c gets assigned to $result. An assignment can be an expression.
$a = ''
$b = ''
$c = 'hi'
[void](
($result = $a) -or
($result = $b) -or
($result = $c))
$result
output
hi
What Bash must be doing is implicitly casting the exit code of the commands to a Boolean when passed to the logical operators. PowerShell doesn't do this - but a function can be made to wrap the command and create the same behavior:
> function Get-ExitBoolean($cmd) { & $cmd | Out-Null; $? }
($? is a bool containing the success of the last exit code)
Given two batch files:
#pass.cmd
exit
and
#fail.cmd
exit /b 200
...the behavior can be tested:
> if (Get-ExitBoolean .\pass.cmd) { write pass } else { write fail }
pass
> if (Get-ExitBoolean .\fail.cmd) { write pass } else { write fail }
fail
The logical operators should be evaluated the same way as in Bash. First, set an alias:
> Set-Alias geb Get-ExitBoolean
Test:
> (geb .\pass.cmd) -and (geb .\fail.cmd)
False
> (geb .\fail.cmd) -and (geb .\pass.cmd)
False
> (geb .\pass.cmd) -and (geb .\pass.cmd)
True
> (geb .\pass.cmd) -or (geb .\fail.cmd)
True