1

In basic 'shell', how do I put the result of a string comparison into a boolean variable?

Consider:

isweekday() {
          w=$(date +%w)
          if [[ $w == "0" ]] || [[ $w == "6" ]]; then
                  false
          else
                  true
          fi

  }

One can debate whether it would be clearer or not, but is there a way to assign the result of the 'if' expression to a boolean variable, e.g.

isweekday() {
          w=$(date +%w)
          wd=<boolean result of [[ $w == "0" ]] || [[ $w == "6" ]]>
          return $wd
}

After some experimentation, I got closer to what I want but it still isn't what I'm after:

isweekday() {
  w=$(date +%w)
  [[ $w == "0" ]] || [[ $w == "6" ]] 
}

This works and does not require the conditional, but it looks wrong, however if you do:

if isweekday; then
  echo 'weekday'
fi

you will get the right result. This seems to be because the exit code of 'true' is 0 and the exit code of 'false' is 1 (not quite sure why that is...)

mike
  • 819
  • 4
  • 14
  • Don't think of it as `true` and `false`, but as `success` and `failure`. When a process is successful, it returns 0. When a process fails, it returns non-zero. – William Pursell Apr 04 '22 at 13:07

2 Answers2

2

There are no boolean variables. All shell variables are strings (though there are limited facilities for interpreting them as integer numbers for basic comparisons etc and basic arithmetic).

The exit code 0 is reserved for success; all other exit codes (up to the maximum 255) signify an error (though some nonstandard tools use this facility to communicate non-error results by way of convention; the caller is then assumed to understand and agree on this ad-hoc use of the exit code).

Perhaps then the simplest answer to what you appear to be asking is to save the exit code. It is exposed in the variable $?. But very often, you should not need to explicitly examine its value; indeed, your final isweekday code looks by far the most idiomatic and natural, and returns this code from [[ implicitly.

I don't understand why you think your final code "looks wrong"; this is precisely how you would use a function in a conditional.

However, in some sense, a case statement would look less cluttered here (but this syntax is somewhat jarring at first for other reasons, until you get used to it).

is_weekday () {
    case $(date +%w) in
      0 | 6) return 1;;
    esac
    return 0
}

This is portable to POSIX sh, unlike the Bash-only [[...]] syntax you were using. Perhaps see also Difference between sh and bash

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • thanks for pointing out that the exit code is really what I'm looking at, and that's why /bin/true is 0 and /bin/false is 1 (or more precisely non-zero I guess for false). I had in my head (wrongly) that a function was 'different' since you 'return' from it and not 'exit' from it, but the consistency of the two makes perfect sense now – mike Apr 04 '22 at 12:18
0

The standard approach in Shell is to use the exit code of a command as the true/false value where zero indicates true and non-zero false. Also, I would instead define a function which tests if it's weekend today since that is the exception so to speak. It's also a good idea to define w as a local variable and to quote all variables which could in the general case contain a space or be undefined, something which can lead to a syntax error after variable expansion. Here is my suggestion:

IsWeekend()
{
    local w="$(date +%w)"
    [ "$w" = 0 ] || [ "$w" = 6 ]
}
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
  • great points and yes, I should have had w in quotes and made it local. – mike Apr 04 '22 at 12:20
  • There is ordinarily no way for `date +%w` to output anything which contains spaces or shell metacharacters, though. But always quoting is probably a good basic guidance for beginners. Perhaps see also [When to wrap quotes around a shell variable](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) – tripleee Apr 04 '22 at 12:31
  • `-a` is wrong here, isn't it? The result can't be both 0 and 6 at the same time. Also, `test` is less capable and less robust than than the Bash built-in double brackets `[[` so I don't think this is an improvement really. – tripleee Apr 04 '22 at 12:36
  • @tripleee Ah, of course. Now changed to "or". – August Karlstrom Apr 04 '22 at 13:42
  • @tripleee You're right, it's more flexible to use brackets instead of `test` (I have updated the answer). However, double brackets are an extension to POSIX so I prefer single brackets. – August Karlstrom Apr 04 '22 at 14:15
  • @tripleee A later change to the code may make a no-space value a value with spaces and then you would need to quote the variable in multiple places. Therefor I think quoting all variables is a wise strategy not only for beginners. Then you don't need to consider the special cases. – August Karlstrom Apr 04 '22 at 14:21