1

I have written below script:

#!/usr/bin/bash

STR_1="nfosys"
STR_2="Infosys"

if (( $STR_1 == $STR_2 ))
then
        echo "Strings are equal"
else
        echo "Strings are not equal"
fi

Getting Output:

root:~/Desktop/user_repo/Demo# bash -x test.sh 
+ STR_1=nfosys
+ STR_2=Infosys
+ ((  nfosys == Infosys  ))
+ echo 'Strings are equal'
Strings are equal
root:~/Desktop/user_repo/Demo# 

Ideally it should print "Strings are not equal" statment but i am unable to understand why it is printing "Strings are equal"

Vlastimil Burián
  • 27,586
  • 56
  • 179
  • 309
Poonam
  • 91
  • 2
  • 6
  • Edit the question and show how the values of `nfosys` and `Infosys` are being obtained and what they actually are while the script is being run. – Nasir Riley Mar 27 '22 at 15:32
  • consider "nfosys" and "Infosys" simple string with direct assignment to variable – Poonam Mar 27 '22 at 15:36
  • `==` inside of `(())` is used for comparing numbers, use `[[` instead for strings. – jordanm Mar 27 '22 at 15:41
  • See: [What is the difference between the Bash operators [[ vs [ vs ( vs ((?](https://unix.stackexchange.com/questions/306111/what-is-the-difference-between-the-bash-operators-vs-vs-vs) – ilkkachu Mar 27 '22 at 15:46
  • if i add square bracket then getting below message -root@ip-10-0-45-44:~# sh -x test.sh + STR_1=nfosys + STR_2=Infosys + [[ nfosys == Infosys ]] test.sh: 6: [[: not found + echo Strings are not equal Strings are not equal root@ip-10-0-45-44:~# – Poonam Mar 27 '22 at 15:49
  • @Poonam, run the script with `bash`, not `sh`. Or rather, `chmod +x test.sh` and `./test.sh` so that the hashbang line applies. See: [Does the shebang determine the shell which runs the script?](https://unix.stackexchange.com/questions/87560/does-the-shebang-determine-the-shell-which-runs-the-script/87600#87600) – ilkkachu Mar 27 '22 at 15:53

3 Answers3

7

(( .. )) is an arithmetic construct, and in arithmetic contexts, a string is taken as the name of a variable, and the value of that variable is used. This happens after $var expansions are expanded, so your script looks at variables called nfosys and Infosys. With both variables unset, both are taken to be zero, i.e. equal. But:

$ str1=foo str2=bar foo=1
$ (( $str1 == $str2 )) && echo true || echo false
false   

See e.g. Bash's manual on shell arithmetic:

Shell variables are allowed as operands; parameter expansion is performed before the expression is evaluated. Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax. A shell variable that is null or unset evaluates to 0 when referenced by name without using the parameter expansion syntax.

For string comparison, use

[ "$STR_1" = "$STR_2" ]   # in any POSIX shell, or

[[ $STR_1 = "$STR_2" ]]   # in Bash/ksh/zsh

The former needs quotes due to word-splitting, the latter needs it only on the right-hand side (in bash / ksh) for $STR_2 not to be taken as a pattern.

Also see: What is the difference between the Bash operators [[ vs [ vs ( vs ((?

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
ilkkachu
  • 133,243
  • 15
  • 236
  • 397
1

Using [] instead would give the wanted behavior:

STR_1="nfosys"
STR_2="Infosys"

if [ $STR_1 = $STR_2 ]
then
        echo "Strings are equal"
else
        echo "Strings are not equal"
fi

Output:

+ STR_1=nfosys
+ STR_2=Infosys
+ '[' nfosys = Infosys ']'
+ echo 'Strings are not equal'
Strings are not equal

A good rule of thumb is to also quote your variables, just in case they end up being wrongly interpreted or be expanded/split:

STR_1="nfosys"
STR_2="Infosys"

if [ "$STR_1" = "$STR_2" ]
then
        echo "Strings are equal"
else
        echo "Strings are not equal"
fi

Also, while [] is considered POSIX, using [[]] if your main target is bash, is better.

Editor's note: POSIX only knows single =.

Vlastimil Burián
  • 27,586
  • 56
  • 179
  • 309
Nordine Lotfi
  • 2,200
  • 12
  • 45
  • I tried using above but getting below message -test.sh: 6: [[: not found – Poonam Mar 27 '22 at 15:50
  • if i use single bracket then getting message -test.sh: 6: [: nfosys: unexpected operator – Poonam Mar 27 '22 at 15:52
  • 1
    this is weird. How did you run your script? @Poonam – Nordine Lotfi Mar 27 '22 at 15:55
  • 1
    Also, thanks for the editor's note ;) I forgot to take this into account – Nordine Lotfi Mar 27 '22 at 16:06
  • @Poonam Pass the script through shellcheck.net. I suspect you have combined parts of several different answers. – Paul_Pedant Mar 27 '22 at 16:18
  • Why show that `[ $STR_1 = $STR_2 ]` (without the quotes) at all? That's very wrong and a command injection vulnerability in shells such as bash. `[ $STR_1 = $STR_2 ]` should be an example of something **not** to do. – Stéphane Chazelas Mar 27 '22 at 17:43
  • that's true, but I only showed that to emphasize that "this work as it is if you just use [ instead of..." by reusing their own stated example :) And yes, I didn't take into account code injection but I did said quoting was a good rule of thumb and what not @StéphaneChazelas – Nordine Lotfi Mar 27 '22 at 17:58
0

Thanks All. i have restarted my session and change to single square bracket -

#!/usr/bin/bash

STR_1="nfosys"
STR_2="Infosys"

if [ $STR_1 == $STR_2 ]
then
        echo "Strings are equal"
else
        echo "Strings are not equal"
fi

If i execute with sh test.sh then getting error -

root@ip:~# sh test.sh 
test.sh: 6: [: nfosys: unexpected operator
Strings are not equal
root@ip:~# bash test.sh 
Strings are not equal

If i execute with bash then display correct output without any error

root@ip:~# bash test.sh 
Strings are not equal

Weird before posting question i had tried both ways - sh/bash and with ()/[]. But after restarting session seems working fine.


Editor's refreshed code adhering to POSIX, and some good codex (lower-case variable names, error print to stderr, fixed major == issue, etc.):

#!/bin/sh

str_1=nfosys
str_2=Infosys

if [ "$str_1" = "$str_2" ]; then
    echo "Strings are equal"
else
    echo "Strings are not equal" >&2
    exit 1
fi
Vlastimil Burián
  • 27,586
  • 56
  • 179
  • 309
Poonam
  • 91
  • 2
  • 6
  • 1
    I hope you won't mind some good advice, feel free to edit it... Cheers, and good luck with Bash/shell in general. – Vlastimil Burián Mar 27 '22 at 17:28
  • 1
    `[ $STR_1 == $STR_2 ]` is very wrong even with `bash`. It even introduces a command injection vulnerability in bash. That's because of the missing quotes, not the `==` instead of `=` in that case. Try if you dare after `STR_1='-v a[$(reboot)] -o x' STR_2=x` for instance. – Stéphane Chazelas Mar 27 '22 at 17:47