Mark Baker
Mark Baker

Reputation: 212522

Multiple `if` statements in bash script

I'm trying to write a short bash script that optionally accepts arguments from the command line, or prompts for their input

if [ [ -z "$message" ] && [ -z "$predefined" ] ] ; then
  read -p "Enter message [$defaultMessage]: " message
  message=${message:-$defaultMessage}
else
  if [ -n "$predefined" ]; then
    if [ -f $base/$environment/vle/data/$predefined.txt ]; then
      echo Predefined message file $predefined.txt does not exist
      exit 1
    fi
  fi
fi

If neither message nor predefined has been passed in as command line arguments, then the code should prompt for a value for message; otherwise if predefined has been passed in as a command line argument, then the script should test for the existence of a file of that name and only continue if the file does exist

But I'm getting the following error

[: -z: binary operator expected

at the first of those if tests

Any help in explaining what's wrong with my syntax for that first if statement? Or providing an alternative syntax to achieve the same objectives.

Upvotes: 1

Views: 27806

Answers (2)

janos
janos

Reputation: 124804

The first if is not well-formed. This would work:

if [ -z "$message" ] && [ -z "$predefined" ]; then

or this:

if test -z "$message" && test -z "$predefined"; then

or this bash-specific, easy but dirty way:

if [[ -z "$message" ]] && [[ -z "$predefined" ]]; then

or this bash-specific proper way:

if [[ -z $message && -z $predefined ]]; then

In this last version the double-quotes are unnecessary, not a typo.

Thanks @mklement0 for the corrections in the bash-specific style, and for this final comment:

I should note that there's one case where double-quoting is still a must inside [[ ... ]], namely if you want a variable reference on the right side of a string comparison (==) to be treated as a literal:

v='[a]'
[[ $v == $v ]] # FALSE!
[[ $v == "$v" ]] # true

Without double-quoting, the right-hand side is interpreted as a pattern. Some people advocate always double-quoting variable references so as not to have to remember such subtleties. That said (from bash 3.2 on), you must NOT double-quote the right operand when regex matching with =~

Upvotes: 9

Keith Reynolds
Keith Reynolds

Reputation: 853

test expression1 -a expression2

is true if both expressions are true.

test expression1 -o expression2

is true if either or both expressions are true.

if [ -z "$message" -a -z "$predefined" ]; then
    read -p "Enter message [$defaultMessage]: " message
    message=${message:-$defaultMessage}
else
    if [ -n "$predefined" -a -f $base/$environment/vle/data/$predefined.txt ]; then
        echo Predefined message file $predefined.txt does not exist
        exit 1
    fi
fi

This was able to combine 4 test into 2 while also getting rid of one nested if expression; then ; fi

Upvotes: 4

Related Questions