Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I compare two strings in if condition in bash

s="STP=20"

if [[ "$x" == *"$s"* ]]

The if condition is always false; why?

like image 715
Sanshayan Avatar asked Dec 23 '13 11:12

Sanshayan


People also ask

Can you compare strings in bash?

The need to compare strings in a Bash script is relatively common and can be used to check for certain conditions before proceeding on to the next part of a script. A string can be any sequence of characters. To test if two strings are the same, both strings must contain the exact same characters and in the same order.

Can I use == to compare two strings?

You should not use == (equality operator) to compare these strings because they compare the reference of the string, i.e. whether they are the same object or not. On the other hand, equals() method compares whether the value of the strings is equal, and not the object itself.

How do you compare strings in if loops?

Use the equals() method to check if 2 strings are the same. The equals() method is case-sensitive, meaning that the string "HELLO" is considered to be different from the string "hello". The == operator does not work reliably with strings. Use == to compare primitive values such as int and char.


3 Answers

Try this: http://tldp.org/LDP/abs/html/comparison-ops.html

string comparison

=

  is equal to

  if [ "$a" = "$b" ]
like image 88
Ferenc Deak Avatar answered Sep 23 '22 12:09

Ferenc Deak


There is a difference in testing for equality between [ ... ] and [[ ... ]].

The [ ... ] is an alias to the test command:

STRING1 = STRING2 the strings are equal

However, when using [[ ... ]]

When the == and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching. If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters. The return value is 0 if the string matches (==) or does not match (!=) the pattern, and 1 otherwise. Any part of the pattern may be quoted to force it to be matched as a string.

The same seems to be true with just the = sign:

$ foo=bar
$ if [[ $foo = *ar ]]
> then
>     echo "These patterns match"
> else
>     echo "These two strings aren't equal"
> fi
These patterns match

Note the difference:

$ foo=bar
> if [ $foo = *ar ]
> then
>     echo "These patterns match"
> else
>     echo "These two strings aren't equal"
> fi
These two strings aren't equal

However, there are a few traps with the [ $f00 = *ar ] syntax. This is the same as:

test $foo = *ar

Which means the shell will interpolate glob expressions and variables before executing the statement. If $foo is empty, the command will become equivalent to:

test = *ar  # or [ = *ar ]

Since the = isn't a valid comparison operator in test, you'll get an error like:

bash: [: =: unary operator expected

Which means the [ was expecting a parameter found in the test manpage.

And, if I happen to have a file bar in my directory, the shell will replace *ar with all files that match that pattern (in this case bar), so the command will become:

[ $foo = bar ]

which IS true.

To get around the various issues with [ ... ], you should always put quotes around the parameters. This will prevent the shell from interpolating globs and will help with variables that have no values:

[ "$foo" = "*ar" ]

This will test whether the variable $foo is equal to the string *ar. It will work even if $foo is empty because the quotation marks will force an empty string comparison. The quotes around *ar will prevent the shell from interpolating the glob. This is a true equality.

Of course, it just so happens that if you use quotation marks when using [[ ... ]], you'll force a string match too:

foo=bar
if [[ $foo == "*ar" ]]
then
    echo "This is a pattern match"
else
    echo "These strings don't match"
fi

So, in the end, if you want to test for string equality, you can use either [ ... ] or [[ ... ]], but you must quote your parameters. If you want to do glob pattern matching, you must leave off the quotes, and use [[ ... ]].

like image 28
David W. Avatar answered Sep 23 '22 12:09

David W.


To compare two strings in variables x and y for equality, use

if test "$x" = "$y"; then
   printf '%s\n' "equal"
else
   printf '%s\n' "not equal"
fi

To test whether x appears somewhere in y, use

case $y in
   (*"$x"*)
      printf '%s\n' "$y contains $x"
      ;;
   (*)
      printf '%s\n' "$y does not contain $x"
      ;;
esac

Note that these constructs are portable to any POSIX shell, not just bash. The [[ ]] construct for tests is not (yet) a standard shell feature.

like image 39
Jens Avatar answered Sep 25 '22 12:09

Jens