2

This stackoverflow answer explains what the Linux true command is. My question, does Powershell (v5/v6) offers also a true command?

I already googled around, used Get-help *true*, but could not find anything about it.

Thx

mklement0
  • 382,024
  • 64
  • 607
  • 775
Moerwald
  • 10,448
  • 9
  • 43
  • 83

2 Answers2

4

In short:

  • There is no PowerShell equivalent to the true and false Unix utilities.

  • Because PowerShell's conditionals and error handling work very differently than in POSIX-like shells such as bash, there is no need for them.

The primary use of Unix utility true is to reset the exit code to 0 in situations where you deliberately want to ignore a previous command's failure (signaled via a nonzero exit code) in POSIX-like shells such as bash, such as in conditionals or with the abort-on-unhandled-failures option set -e in effect.
Neither true nor its counterpart, false, produce any output - their sole purpose is to set an exit code.

PowerShell doesn't use exit codes natively (though you can set them for the benefit of outside callers with exit <n>), and its conditionals do not act on them.

  • PowerShell's automatic $? variable is similar in the abstract to $? in POSIX-like shells, except that it reports a Boolean, whereas POSIX-like shells report the exit code; that is $? containing 0 in a POSIX-like shell is akin to $? containing $true in PowerShell.

  • PowerShell never acts on $? implicitly, but you can use it in PowerShell conditionals explicitly, so that the following two - contrived for simplicity - commands would be equivalent:

    # POSIX-like shells:
    # Event though the `ls` command fails `|| true` makes the overall
    # command succeed.
    if ls /nosuchfile || true; then echo success; fi
    
    # PowerShell:
    # `$?` would reflect `$false` after the failed `ls` command.
    # `$null = $null` is a dummy command that resets `$?` to `$true`
    # `$?` is then *output* for the `if` to test.
    if ($(ls /nosuchfile; $null = $null; $?)) { 'success' }
    

While PowerShell has the automatic $true and $false variables (conceptually, constants), they are Boolean values used for comparison with output (data), not commands that set invisible status information (exit codes).

Read on for background information.


Conditionals in POSIX-like shells vs. in PowerShell

In POSIX-like shells such as bash, conditionals operate on the exit codes of commands, i.e., (post-execution) status information, not their output.

By contrast, PowerShell conditionals operate on command or expression output, i.e. data, not status information.

In short:

  • Conditionals in POSIX-like shells act on invisible exit codes and pass success output (stdout output) through.

  • Conditionals in PowerShell act on success output and consume it in the process.

Both shells pass error output (stderr) through.


If you want a PowerShell conditional to act on a command's (post-execution) status (success vs. failure):

You can use the automatic $? variable, whose behavior depends on whether the command at hand is a PowerShell-native one or an external program such as a Unix utility:

  • External programs: If the program's exit code is 0, $? reflects $true, otherwise $false

    • This is akin to the built-in $? variable in POSIX-like shells such as bash, except that $? there contains the actual exit code; that is, $? containing 0 in a POSIX-like shell is the same as $? containing $true in PowerShell after execution of an external program.

      • To get the actual exit code in PowerShell, use the automatic $LASTEXITCODE variable, which reflect's the exit code of the most recently executed external program (PowerShell-native commands generally do not set exit codes, though you can use exit <n> in scripts, primarily for reporting exit codes to outside callers).
  • PowerShell-native commands (cmdlets, functions, scripts): $? is $true if the command did not fail fundamentally and did not write to PowerShell's error stream (such as with Write-Error; note that stderr output from external programs by default does not write to PowerShell's error stream).

    • Note that $? therefore does not necessarily tell you whether a given command considered its overall execution successful or not; $? being $false merely tells you only that some error was reported.
    • However, you can wrap a command invocation in a try { ... } catch { ... } statement, which helps you distinguish non-terminating from terminating errors (by default only the latter trigger the catch block);

Use of $? is not common in PowerShell, because failure is typically handled with the
-ErrorAction common parameter / $ErrorActionPreference preference variable and/or try { ... } catch { ... } statements.

That said, these methods cannot be used on external programs, where testing $? or $LASTEXITCODE is a must to detect failure.
This GitHub discussion and this RFC draft call for better integration of external programs with PowerShell's error handling.

For a comprehensive overview of PowerShell's error handling, see this GitHub issue.

mklement0
  • 382,024
  • 64
  • 607
  • 775
1

What you're looking for is the about_Automatic_Variables topic where the variables $true and $false are described.

I wrote this out as an answer because I wanted to point out a "gotcha" I ran into dealing with these values: 0 and 1 are equal to $false and $true, respectively.

$false -eq 0 # => True
$false -eq $null # => False - not false-y?

$true -eq 1 # => True
$true -eq 2 # => True - appears to be truth-y

Meanwhile, the string 'false' is not.

$false -eq 'False' # => False

Also, for some reason, $false is equal to an empty string:

$false -eq '' # => True
$false -eq [string]::Empty # => True

While the string 'true' IS equal to $true (indeed, any non-zero number, and any non-empty string is):

$true -eq 'True' # => True

In the exploration of writing this answer, I realized a lot of $true comparisons evaluate to True, so it's safe to assume comparisons to the bool constants are truth-y/false-y.

Here are the values that compare to $false (which makes the following comparisons return $true):

$false -eq ''  # Empty string
$false -eq 0   # Zero
$false -eq @() # Empty array

The only comparison I found that failed a test to both is $null (so not 100% false-y):

$false -eq $null # => False
$true -eq $null  # => False

One last example edge-case that evaluates to $false in some other languages is an empty [hashtable] (or dictionary):

$true -eq @{} # => True

To sum up what @Joey stated in the comments:

╦═════════════════════╦═════════════════════════╗
║ Falsy               ║ Truthy                  ║
╠═════════════════════╬═════════════════════════╣
║ 0                   ║ Non-0                   ║
║ @()                 ║ @(1)                    ║
║ @(0)                ║ @(0, 1)                 ║
║ [string]::Empty     ║ Non-empty string        ║
║ $false              ║ $true                   ║
║ 0-backed enum value ║ Any non-0 enum value    ║
║ $null               ║ Any non-$null reference ║
╚═════════════════════╩═════════════════════════╝
mklement0
  • 382,024
  • 64
  • 607
  • 775
Maximilian Burszley
  • 18,243
  • 4
  • 34
  • 63
  • 1
    Your equality comparisons here employ a lot of the automatic type conversions. Most notably, for `-eq` the type of the right operand is converted to the type of the left one, if possible and necessary (unless the left one is an array). So comparing to `0`, the empty string, etc. will do a type conversion to boolean and, as you'd expect, most non-null, non-zero, non-default values are actually true. Arrays are special; arrays with one element are as truthy or falsey as that element. Arrays with multiple elements are truthy, but `-eq` behaves differently as it then acts as a filter instead. – Joey Mar 26 '19 at 13:49
  • 1
    Basically: To test truthiness, use `if`, as that will behave predictably, even with arrays. Don't use `-eq`, which is not a true equivalence relation in PowerShell (as it is in many other scripting languages as well). – Joey Mar 26 '19 at 13:50
  • 1
    @Joey I wasn't aware of the type coercion in effect, but I agree with your assessment; you should not use comparisons to booleans for a logic step. If you're working with a known bool, use it by itself: `if ($bool) {` or `if (-not $bool) {` I believe the array comparison stuff is powershell automatically unrolling single-element arrays into a scalar for the compare. – Maximilian Burszley Mar 26 '19 at 13:54
  • 1
    To make it short: Falsey: `0`, empty arrays, arrays with only one element that is falsey, the empty string, `$null`, `$false`, enum values having the numeric value `0`. Truthy: Any number or enum value not equal to `0`, arrays with more than one element, arrays with only one element that is truthy, any non-empty string, any other non-`$null` reference – Joey Mar 26 '19 at 13:55
  • Coercion for single-element arrays is well-defined. Comparison with operators with the array as the _left_ operand is instead filtering the array. In this case there's no auto-unrolling. As far as I remember that only applies to pipelines. – Joey Mar 26 '19 at 13:57
  • Note however that 2 -eq $true evaluates to False. – Walter Mitty Mar 26 '19 at 14:52
  • 1
    @WalterMitty That's because `$true` gets coerced into an `[int]` which is represented as `1`. So yes, `2 -eq 1` is False. – Maximilian Burszley Mar 26 '19 at 14:53
  • 1
    @mklement0 It's the only one that surprised me since `[bool]$null` is `$false`. I need to revisit this answer to be more clear as I never really dived into this topic before; just knew how to do comparisons. – Maximilian Burszley Mar 26 '19 at 17:41
  • An empty hashtable is truthy, because it is considered a _single object_ (not a collection), and single objects are always truthy (leaving numbers, Booleans, and strings aside), e.g., `[bool] (new-object pscustomobject)` – mklement0 Mar 26 '19 at 17:44
  • The bottom half of https://stackoverflow.com/a/53108138/45375 has a comprehensive summary of implicit to-Boolean coercion (I hope); I just added the `$false -eq $null` pitfall. @Joey: good summary, but there's another edge case: `[bool] (, (, $false))` is `$true`. – mklement0 Mar 26 '19 at 18:35
  • 1
    @mklement0: Thanks, it's been a while that I've been looking into those things (basically back when I was a reviewer for the PowerShell Cookbook 2nd ed. and was still actively golfing). Most of TheIncorrigible's confusion stemmed from muddling boolean coercion with implicit conversion, as `-eq` does more things than `if`, and the comment just got ... longer ;-) – Joey Mar 27 '19 at 09:28