8
s="STP=20"

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

The if condition is always false; why?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Sanshayan
  • 1,076
  • 1
  • 11
  • 16
  • 1
    What is value of `$x`? – anubhava Dec 23 '13 at 11:24
  • Try `echo "$x"` before the `if` statement. This line of code shall work as expected. – starrify Dec 23 '13 at 11:24
  • thanks. my x variable is assigned by awk x=$(awk '{printf "%s ", $17}' this) – Sanchai_28 35 secs ago edit – Sanshayan Dec 23 '13 at 11:27
  • Can you do **`echo "$x" | cat -vte`** and tell us the output. – anubhava Dec 23 '13 at 11:29
  • 1
    Closely related questions: [SO 20742474](http://stackoverflow.com/questions/20742474), [SO 20780315](http://stackoverflow.com/questions/20780315), [SO 20780890](http://stackoverflow.com/questions/20780890), [SO 20781258](http://stackoverflow.com/questions/20781258). Not quite duplicates, but the same data stream. – Jonathan Leffler Dec 27 '13 at 15:03
  • Possible duplicate of: https://stackoverflow.com/q/2237080/6862601 – codeforester Nov 18 '18 at 07:31

5 Answers5

7

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

string comparison

=

  is equal to

  if [ "$a" = "$b" ]
Ferenc Deak
  • 34,348
  • 17
  • 99
  • 167
  • thanks. my x variable is assigned by awk x=$(awk '{printf "%s ", $17}' this) – Sanshayan Dec 23 '13 at 11:26
  • 1
    I remember `==` also works for comparison and there's no difference between `=` and `==`.. – starrify Dec 23 '13 at 11:27
  • 1
    There is a difference if you use ``[ ]`` (and you should not do that, please prefer ``[[ ]]``). ``=`` and ``==`` work exactly the same inside ``[[ ]]`` conditional, but only ``=`` is available in ``[ ]``. See [this](http://mywiki.wooledge.org/BashFAQ/031) and [this](http://mywiki.wooledge.org/Bashism) for more info. – Aleks-Daniel Jakimenko-A. Dec 23 '13 at 11:39
6

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 [[ ... ]].

David W.
  • 105,218
  • 39
  • 216
  • 337
1

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.

Jens
  • 69,818
  • 15
  • 125
  • 179
0

I do not know where you came up with the *, but you were real close:

s="STP=20"
if [[ "STP=20" == "$s" ]]; then
    echo "It worked!"
fi
cforbish
  • 8,567
  • 3
  • 28
  • 32
  • `bash` allows pattern matching inside `[[`, so the original OP's code should evaluate to true if `$x` contains `$s` as a substring. – chepner Dec 23 '13 at 18:23
-1

You need to escape = using \ in the string s="STP=20"

s="STP\=20"

if [[ "STP\=20" == "$s" ]]; then echo Hi; else echo Bye; fi
Suvarna Pattayil
  • 5,136
  • 5
  • 32
  • 59