Operating System - Linux
1751968 Members
4456 Online
108783 Solutions
New Discussion юеВ

Re: double vs single brackets in shell script tests

 
Scott Lindstrom_2
Regular Advisor

double vs single brackets in shell script tests

I have read everything I can get my hands on about this, but still cannot figure out when I should use single brackets and when I should use double brackets.

Here is the code snippet that raised this issue for me:

#!/usr/bin/sh

if [[ $DEVICE = 'ftp' ]]
then continue
fi
if [[ $USER = 'reboot' ]]
then continue
fi
if [[ $USER = 'root' ]]
then continue
fi
if [[ $USER = 'wtmp' || $USER < 'a' ]]
then break
fi
if [[ $USER = 'cduser' && $DEVICE = 'ftp' ]]
then continue
fi
if [[ $DEVICE = 'console' ]]
then continue
fi

When I trace the code I get:

+ [[ remshd = ftp ]]
+ [[ root = reboot ]]
+ [[ root = root ]]
+ [[ root = wtmp ]]
+ [[ root < a ]]
+ [[ root = cduser ]]
+ [[ remshd = console ]]

I would have expected the third line should have been true. (The trailing spaces are odd).

If I change some of the double brackets to single brackets as follows:

#!/usr/bin/sh

if [[ $DEVICE = 'ftp' ]]
then continue
fi
if [ $USER = 'reboot' ]
then continue
fi
if [ $USER = 'root' ]
then continue
fi
if [[ $USER = 'wtmp' || $USER < 'a' ]]
then break
fi
if [[ $USER = 'cduser' && $DEVICE = 'ftp' ]]
then continue
fi
if [ $DEVICE = 'console' ]
then continue
fi


Then the code runs fine:

+ [[ remshd = ftp ]]
+ [ root = reboot ]
+ [ root = root ]

But I don't understand why.

I did try to change all the double bracket tests to single brackets, but then the shell objected on the compound conditions.

I would very very grateful to anyone could clear up why this happens and perhaps explain in simpler terms than I have
been able to find on how to decide which form to use.

Scott







18 REPLIES 18
Oviwan
Honored Contributor

Re: double vs single brackets in shell script tests

Hey

I guess double brackets is ksh style but you are using sh. check the man pages for each shell.

Regards
A. Clay Stephenson
Acclaimed Contributor

Re: double vs single brackets in shell script tests

The rules are rather simple and in general you should always use double brackets because they are internal to the shell and thus more efficient rather than invoking the external test command. Moreover, there are more tests available with the internal test. The only downside to the [[..]]'s is that not all shell recognize this construct but any modern shell does.

The main gotcha is that the syntax for the logical operators are different in the two version

if [[ "${A}" = "Hook" && "${B}" = "Smee" ]]
is equivalent to:
if [ "${A}" = "Hook" -a "${B}" = "Smee" ].

Similarly:
if [[ "${A}" = "Hook" || "${B}" = "Smee" ]]
is equivalent to:
if [ "${A}" = "Hook" -o "${B}" = "Smee" ].

It is always a very good idea to enclose the tested variables inside double quotes because should the instantiated variables happen to be null and not enclosed within quotes then a syntax error results. Moreover, without quotes white space is not preserver and that is probably your fundamental problem in your example.


If it ain't broke, I can fix that.
Scott Lindstrom_2
Regular Advisor

Re: double vs single brackets in shell script tests

Oviwan -

I have read the man page and unfortunately it makes no sense on this subject. It talks about word splitting, etc but does not have anything (at least that I understand) that helps me.

Scott Lindstrom_2
Regular Advisor

Re: double vs single brackets in shell script tests

Clay -

Let me try quoting the variable names and see what happens. (That's just not something I am used to having to do in other languages I have used).

Scott
Oviwan
Honored Contributor

Re: double vs single brackets in shell script tests

Hey again

man test is more detailed how clay mentioned.

Regards
Dennis Handly
Acclaimed Contributor

Re: double vs single brackets in shell script tests

>It talks about word splitting, etc but does not have anything (at least that I understand)

I think this is exactly your problem. See "Blank Interpretation". For [[ ]] the trailing blanks in $USER are not split.

Note also [[ = ]] is NOT a test for string equality but pattern matching.

Assuming that USER="root ", these are all true:
[[ $USER = r* ]]
[[ $USER = root* ]]

>Clay: you should always use double brackets because they are internal to the shell and thus more efficient

Using tusc, I seen no evidence that test(1) is executed for [ ], both are real shell builtins.

In fact, /usr/bin/test just invokes the Posix shell builtin.

>It is always a very good idea to enclose the tested variables inside double quotes

It appears you don't have to do that for [[ ]]. But still a very good idea.

BUT you must NOT use "" or "" quoting if you want pattern matching.

Scott Lindstrom_2
Regular Advisor

Re: double vs single brackets in shell script tests

Clay -

I changed the third "if" as you suggested and still get the same results:

if [[ "${USER}" = 'root' ]]
then continue
fi


+ [[ remshd = ftp ]]
+ [ root = reboot ]
+ [[ root = root ]]

I also change the single quotes around 'root' to double quotes but this does not seem to have any effect:

if [[ "${USER}" = "root" ]]
then continue
fi


+ [[ remshd = ftp ]]
+ [ root = reboot ]
+ [[ root = root ]]

I am curious, the first if looks like this and seems to work OK:

if [[ $DEVICE = 'ftp' ]]
then continue
fi

+ [[ remshd = ftp ]]

(Note the lack of padding on the right of "remshd").

I can get this to work just by changing to single brackets, but am hoping this will be a good learning opportunity for ma and anyone else reading this thread.

Scott
Scott Lindstrom_2
Regular Advisor

Re: double vs single brackets in shell script tests

Dennis:

>I think this is exactly your problem. >See "Blank Interpretaion". For [[ ]] the >trailing blanks in $USER are not split.

>Note also [[ = ]] is NOT a test for string >equality but pattern matching.

I guess I am being dense here, but I've never worked in a language where xxx did not equal xxx. Otherwise almost all the if statements I've written in my life would be false.

So what do I do if I want string equality and not pattern matching?

Scott
Peter Nikitka
Honored Contributor

Re: double vs single brackets in shell script tests

Hi Scott,

then use [ .. ] - you know the side effects much better than in [[ .. ]] so leave it at old style (IMHO).

mfG Peter
The Universe is a pretty big place, it's bigger than anything anyone has ever dreamed of before. So if it's just us, seems like an awful waste of space, right? Jodie Foster in "Contact"