Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash If-statement to check If string is equal to one of several string literals [duplicate]

Tags:

bash

In my bash script, I am checking that the first argument is either -, 0, or +, using following if statement:

LEVEL=$1
if [ "$LEVEL" -ne "-" ] && [ "$LEVEL" -ne "0" ] && [ "$LEVEL" -ne "+" ]
then
     echo "The value of LEVEL must be either -, 0, or +!"
     exit 1
fi

But it's giving me the error [: -: integer expression expected, referring to the line with the if statement conditions.

I've been trying lots of different syntaxes (e.g., double vs single brackets, quoting vs non-quoting the variables and string literals), but I can't figure it out.

like image 747
synaptik Avatar asked Mar 07 '14 19:03

synaptik


People also ask

How do I compare two string variables in bash?

When comparing strings in Bash you can use the following operators: string1 = string2 and string1 == string2 - The equality operator returns true if the operands are equal. Use the = operator with the test [ command. Use the == operator with the [[ command for pattern matching.

What is == in bash script?

== is a bash-specific alias for = and it performs a string (lexical) comparison instead of a numeric comparison. eq being a numeric comparison of course.

How do you check if a variable is equal to a string in bash?

You can check the equality and inequality of two strings in bash by using if statement. “==” is used to check equality and “!= ” is used to check inequality of the strings. You can partially compare the values of two strings also in bash.

Is not equal to in bash?

The not equal function in Ubuntu bash is denoted by the symbol “-ne,” which would be the initial character of “not equal.” Also included is the “! =” operator that is used to indicate the not equal condition.


2 Answers

The conventional approach, compatible with POSIX sh rather than leveraging bashisms, is to use the case statement:

case $level in
   -|0|+)
     echo "Got it!" ;;
   *)
     echo "Not a valid value" ;;
esac

That said, if you wanted to use test, you could do that too:

if [ "$LEVEL" != "-" ] && [ "$LEVEL" != "0" ] && [ "$LEVEL" != "+" ]; then
  ...
fi

!= is the negating string comparison operator, and = (not ==) is the POSIX-compatible positive-matching one. (Bash extends POSIX to support == in test, but making a habit of using this extension will get you into trouble if you try to write code for a pure POSIX shell later).


Below here, there be bashisms! (Above is POSIX compliant).


In a comment, a follow-up question was asked, in terms of whether the set of possible characters could be read from a variable. In general, yes, though there are some caveats:

# no spaces in possible_levels, as we're using it to form a pattern
possible_levels='-0+'
possible_levels_pattern="[${possible_levels}]"
if [[ $value = $possible_levels_pattern ]]; then
  echo "value contains a valid level"
fi

...As an even shorter approach that allows your input string to be used unmodified, and is almost correct:

# caveat: will say some incorrect strings, like "- 0" or "0 +", are valid levels
possible_levels=' - 0 +'
check_level() {
  [[ " $possible_levels " = *" $1 "* ]] && echo "Value is a valid level"
}

...or, as yet another implementation (verbose, but correct in the particulars):

possible_levels=' - 0 +'
read -a possible_levels_array <<<"$possible_levels"
check_level() {
  local possible_level
  local value=$1
  for possible_level in "${possible_levels_array[@]}"; do
    [[ $value = "$possible_level" ]] && return 0
  done
  return 1
}

if check_level "$value"; then
  echo "$value is a valid level"
else
  echo "$value is not a valid level"
fi

Obviously, this is a lot of work, and in general, just hardcoding the comparisons when appropriate (and possible without a loss of safety) will save you trouble over trying to make things more generic than they truly need to be.

Now, if we could pass in the variable as an associative array, without needing to support the silly space-separated-list thing, that makes it much shorter:

declare -A possible_levels=( [-]=1 [+]=1 [0]=1 )
if [[ ${possible_levels[$value]} ]]; then
  echo "valid level"
else
  echo "invalid level"
fi
like image 51
Charles Duffy Avatar answered Sep 20 '22 15:09

Charles Duffy


You can use [[ and ]] use a selector:

if [[ "$LEVEL" == [0+-] ]]; then
  echo "got it"
fi
like image 27
anubhava Avatar answered Sep 22 '22 15:09

anubhava