0

If I don't care about compatibility or portable issues, would I still need to use test construction [...] in Bash?

Many tutorials/books tell that [[...]] is better and more flexible than [...] e.g. [[...]] is support glob/regex, but today I still see many people prefer to use [...] as standard form.

What is a reason behind this? What [...] can do but [[...]] can not do?

Jared Rummler
  • 37,824
  • 19
  • 133
  • 148
fronthem
  • 4,011
  • 8
  • 34
  • 55
  • 3
    `[...]` can cause errors that `[[ ... ]]` won't if you don't use proper whitespace and quote parameter expansions correctly. Otherwise, it is used solely to keep the shell script portable. – chepner Aug 31 '15 at 21:27
  • `[` is (more like) an ordinary command, with the same interpretation of parameters as any other command. The `[[` command interprets arguments differently from other commands. If you don't mind winding your brain around different ways that arguments are handled, use `[[`. You'll be in good company — witness the earlier comment. But `[` uses the same notations as any other command so it is a whole heap easier to use than `[[`. – Jonathan Leffler Aug 31 '15 at 21:32
  • When I start to learn Bash, several forms of test construction quite bother me, I always use Bash as a glue code for my project and I just need a best solution which don't care about portability/compatible issue. BTW, any important note about `[..]` please answer me below. – fronthem Aug 31 '15 at 21:39
  • 1
    Most of the errors I see people make with `[` lead me to think they are applying a 3rd set of rules to it that don't apply to either `[[` or an ordinary command. If anything, I'd recommend only using the name `test` for that command if you are going to use it. – chepner Aug 31 '15 at 21:47
  • 1
    The generally received wisdom is "use `[[`" when portability isn't an issue. Portability is an issue for me, and I've been shell programming for a long time — I prefer `[` because it is simpler for me to use because it is 'just a regular command with no special cases' (which is also not quite true, but the special cases have not caused me problems because I internalized the issues 30 years ago). Your choice, but if you're really sure that portability isn't an issue, then probably go with `[[`. – Jonathan Leffler Aug 31 '15 at 21:53
  • Could I ask you something? Normally, when people keep using `[` or use some old syntax that mean they want stick on `POSIX` right? – fronthem Sep 01 '15 at 07:41

2 Answers2

1

I found one bit of functionality that [ implements but [[ does not. However, it's not something you should be using anyway, so I wouldn't call it a reason to use [ over [[.

The -a and -o operators for boolean AND and OR are supported by test:

if [ 3 -eq 3 -a 4 -eq 4 ]; then
    echo true
fi

However, trying to use them with [[ is a syntax error:

# The correct version is
# if [[ 3 -eq 3 && 4 -eq 4 ]]; then echo yay; fi
$ if [[ 3 -eq 3 -a 4 -eq 4 ]]; then echo yay; fi
bash: syntax error in conditional expression
bash: syntax error near `-a'

But if you are using [[, you would use && and || instead, even if -a and -o were supported. Further, even the POSIX standard recommends using [ ... ] && [ ... ] in place of -a (and [ ... ] || [ ... ] instead of -o); the two operators are extensions that aren't required of a conforming POSIX implementation.


Other reasons, aside from portability concerns, are simply going to be matters of opinion.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    I wouldn't say that `[[` doesn't implement the functionality of `-a` and `-o`; I'd say that they're spelled `&&` and `||` there. – Charles Duffy Aug 31 '15 at 21:57
  • I agree with Charles Duffy. But, more generally, most of the advantages of `[[` can be spun as functionality deficits. For example, consider `foo='3 -lt 4' ; if [ $foo ] ; then ...`. – ruakh Aug 31 '15 at 22:02
  • Fair enough, but it is true you cannot simply "wrap" 100% of valid `[ ... ]` commands in another layer of square brackets and have it work. (My original answer was going to be that there is *nothing* that `[` supports that `[[` does not, until I stumbled on this little tidbit, ruakh's valid point aside.) – chepner Aug 31 '15 at 22:24
1

Other than the portability benefits of [ and the newer features and safety/correctness properties of [[ that have already been discussed there is one downside to using [[ that is worth being aware of (to my mind).

Specifically, what happens when you use it to validate/etc. numeric values.

I asked a question here about it.

I also discussed it in the comments on this answer.

Specifically, this

foo=bar
[ 5 -eq "$foo" ]

will output an error and [ will return 2 whereas this (with or without quotes around the variable)

foo=bar
[[ 5 -eq "$foo" ]]

will silently return 1 and this

bar=5
foo=bar
[[ 5 -eq "$foo" ]]

will return 0.

That is [[ evaluates bare-variables recursively. It also, as indicated in ruakh's comment on chepner's answer will expand expressions in variables.

So

foo="10 / 2"
[[ 5 -eq "$foo" ]]

will also return true.

Now, this may be exactly what you want but means you have to work harder to validate input/etc. then you would with [.

Community
  • 1
  • 1
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • Interesting. POSIX doesn't seem to specify this kind of recursive lookup, although it doesn't forbid it, either. In `dash`, `echo $(( foo ))` is an error, but `echo $(( $foo ))` works. A third level of indirection is right out; with `baz=foo`, neither `echo $(( baz ))` nor `echo $(( $baz ))` works. – chepner Sep 01 '15 at 04:10
  • @chepner `echo $(( foo ))` when `$foo` contains a numeric value is POSIX specified to work (and does seem to in `dash` here, and `dash -c 'echo $(( foo ))'` returns `0` as expected. `dash -c 'echo $(( $foo ))'` on the other hand is an error the same as `dash -c 'echo $(( ))'` is) and yes, what happens when `$foo` *doesn't* contain a numerical value is unspecified which is what bash hangs its behavior on. Yeah, `dash` has the single-level expansion that makes more sense to me (though the error indicates it expanded the variable and *then* blew up as opposed to not expanding and blowing up). – Etan Reisner Sep 01 '15 at 13:07