pepero pepero - 1 month ago 16
Bash Question

command concatenation in bash

I want to invoke a function with some input checks (the input should be an integer between 1-21). If ok, then do the echo "invoke", else just print a message about invalid input.

I tried with the following simplified example, it works for the invalid case, but does not invoke for the valid case. what is wrong?

function _check_num ()
{
[[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -ge 1 -a "$1" -le 21 ] || echo "input should be (1-21)" && return 1 // one-liner
}

function _call()
{
_check_num $1 && echo "invoke only if input is 1-21" // does not invoke given valid input
}


Note: please explain me the root cause of this one-liner case.

Answer

Do not use chains of && and || as a replacement for an if statement. && and || have equal precedence, so a && b || c runs c if either a or b fail; it is not equivalent to if a; then b; else c; fi.

a && b || c && d is parsed as ((a && b) ||c) && d, not (a && b) || (c && d).

Use an expicit if statement to make your code readable. (Also, don't use -a inside [...]; it is considered ambiguous and obsolete.)

function _check_num ()
{
    if [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -ge 1 ] && [ "$1" -le 21 ]; then
        return 0
    else
        echo "input should be (1-21)" >&2
        return 1
    fi
}

The less readable version would be something like the following, uses braces to properly group the commands.

function _check_num ()
{
  {
    [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -ge 1 ] && [ "$1" -le 21 ]
  } || {
    echo "input should be (1-21)" >&2 && return 1
  }
}
Comments