It's helpful to remember that [
is actually a command, also available as test
. In bash like in most other Bourne-like shells, it's a builtin command, so you can see the documentation with info bash [
or by searching inside man bash
(also man builtin
on some systems where bash is also the system's sh
).
In that documentation:
test
and [
evaluate conditional expressions using a set of rules
based on the number of arguments.
- 0 arguments
The expression is false.
- 1 argument
The expression is true if and only if the argument is not
null.
- 2 arguments
[...]
- 3 arguments
[...]
Pedantically speaking, when using [
instead of test
for the command, the final (required) ]
is also an argument, but that's not counted in the numbers above (which come straight from the bash documentation). Anyway...
The two-argument rules are various tests, and the three-argument ones are generally comparisons. When you put a space around the =
, you get three arguments. But when you put it all together, you get one argument, and as you can see, if that argument isn't null, it returns true.
Well, technically, since you forgot the quotes around the parameter expansions in [ $S1=$S2 ]
(and everywhere else), $S1
and $S2
are subject to split+glob, so that could result in more arguments passed to the [
command. In bash, like in ksh, that would even constitute a command injection vulnerability.
For instance, if $S1
was defined as S1='-v xx[$(reboot)] -o yy'
and $S2
as S2='zz'
, the splitting part, with the default value of $IFS
would yield -v
, xx[$(reboot)]
, -o
, yy=zz
; [...]
being a globbing operator the xx[$(reboot)]
could expand to xxo
, xxt
if there were such files in the current directory, but if not, xx[$(reboot)]
would be passed as-is to [
and -v array[index]
in bash's [
builtin is a test to check whether the array element is set, and $(reboot)
would be expanded to the output of the reboot
command to determine the index.
The correct syntax is [ "$S1" = "$S2" ]
, where it's also critical not to forget the quotes.
[ "$S1" = "$S2" ]
. Otherwise, if$S1
or$S2
contain wildcard or spaces, they would be expanded (e.g. try both withS1='a = a -o a'
andS2='b'
). In ksh, bash and zsh, you can use[[ $S1 = $S2 ]]
, because[[
…]]
is special shell syntax whereas[
is an ordinary command with a funny name. Note that you also need spaces around the brackets in either case. – Gilles 'SO- stop being evil' Feb 18 '11 at 21:08[[ "$S1" = "$S2" ]]
or at least[[ $S1 = "$S2" ]]
.[[ $S1 = $S2 ]]
is a test of whether the contents of$S1
matches the pattern stored in$S2
. For instance,S1='[x]'; [[ $S1 = $S1 ]]
returns false because[x]
doesn't match the[x]
pattern. Quoting$S2
causes the contents to be take literally, not as a pattern. – Stéphane Chazelas Aug 27 '23 at 16:41