What are the PowerShell equivalents of Bash's && and || operators?

后端 未结 4 1348
一整个雨季
一整个雨季 2020-11-27 16:56

In Bash I can easily do something like

command1 && command2 || command3

which means to run command1 and if command1 succeeds to run

相关标签:
4条回答
  • 2020-11-27 17:30

    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.

      • Now that PowerShell has gone open-source, an issue has been opened on GitHub.
      • The tokens && and || are currently reserved for future use in PowerShell, so there's hope that the same syntax as in Bash can be implemented.
        (As of PSv5.1, attempting something like 1 && 1 yields error message The token '&&' is not a valid statement separator in this version.)

    Why PowerShell's -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.

      • However, the error information resulting from nonexistent file 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).

    0 讨论(0)
  • 2020-11-27 17:33

    We can use try catch finally method instead of using && method in powershell.

    try {hostname} catch {echo err} finally {ipconfig /all | findstr bios}
    
    0 讨论(0)
  • 2020-11-27 17:38

    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
    
    0 讨论(0)
  • 2020-11-27 17:45

    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
    
    0 讨论(0)
提交回复
热议问题