3
my@comp:~/wtfdir$ cat wtf.sh
str1=$(echo "")
str2=$(echo "")

if [ $str1 != $str2 ]; then
  echo "WTF?!?!"
fi
my@comp:~/wtfdir$ ./wtf.sh
WTF?!?!
my@comp:~/wtfdir$

WTF is going on here?!

How I wrote the above code: Googling "bash compare strings" brought me to this website which says:

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.

Yet I'm getting the above?

What am I not understanding? What am I doing wrong?

3
  • 5
    Quotes matter. Run [ "$str1" != "$str2" ] Commented May 1, 2019 at 20:03
  • 2
    Also, keep in mind that [ isn't special syntax, it's just a command; its arguments go through the same expansion phases as every other command. If ls $empty runs just ls with no arguments, then [ $empty != $empty ] just runs [ != ]. (The special-syntax alternative to test is [[, and it doesn't have the problem you're asking about here). Commented May 1, 2019 at 20:06
  • 2
    str1= is sufficient to assign an empty value to str1. Commented May 1, 2019 at 20:10

1 Answer 1

13

You aren't running a comparison at all, because you aren't using quotes where they're mandatory. See the warning from http://shellcheck.net/ about unquoted expansions at SC2086.

If both string are empty, then:

[ $str1 != $str2 ]

...evaluates to...

[ != ]

...which is a test for whether the string != is nonempty, which is true. Change your code to:

[ "$str1" != "$str2" ]

...and the exact values of those strings will actually be passed through to the [ command.


Another alternative is using [[; as described in BashFAQ #31 and the conditional expression page on the bash-hackers' wiki, this is extended shell syntax (in ksh, bash, and other common shells extending the POSIX sh standard) which suppresses the string-splitting behavior that's tripping you up:

[[ $str1 != "$str2" ]]

...requires quotes only on the right-hand side, and even those aren't needed for the empty-string case, but to prevent that right-hand side from being treated as a glob (causing the comparison to always reflect a match if str2='*').

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.