[pacman-dev] [PATCH 1/2] Changing [ to [[ and ((

Isaac Good pacman at isaac.otherinbox.com
Thu Nov 12 20:23:42 EST 2009


On Thu, Nov 12, 2009 at 11:52:31PM +0000, Cedric Staniewski wrote:
> Allan McRae wrote:
> > Cedric Staniewski wrote:
> >> We could remove the quotes here, too.
> >>
> > 
> > Hmmm...  can we.  I know we can when there are spaces in a single
> > variable, but for some reason I thought quotes were needed when joining
> > multiple variables like that.  I could be wrong...
> > 
> 
> [[ behaves quite different compared to [ in this aspect, but as far as I
> know, you do not need quotes to join variables as long as there are no
> spaces between the variables ;). There are several exceptions though,
> like cd for example, which require quotes even for single variables when
> they contain spaces. I think this has something to do with the type of
> the command. Builtins/external commands (usually) need quotes whereas
> everything else should work without.
> In my opinion, it is often not obvious whether they are required or not
> which is why I tended to use more quotes than actually were needed. I am
> fairly familiar with quoting by now and can use both "quoting styles",
> but I think it would probably be a good idea to decide for one. Using
> just as much quotes as required would be a little bit shorter, but using
> quotes `where possible` may be a little bit more foolproof.
> 
> $ a=" a d"
> $ b=" e"
> $ c=$a:$b
> $ echo "$c"
>  a d: e
> $
> $
> $ filename="a d e"
> $ suffix=".f"
> $ [ -e ${filename}${suffix} ] && echo 1
> bash: [: too many arguments
> $ [[ -e ${filename}${suffix} ]] && echo 1
> $ touch "${filename}${suffix}"
> $ [[ -e ${filename}${suffix} ]] && echo 1
> 1
> $ [[ -e a d e.f ]] && echo 1
> bash: syntax error in conditional expression
> bash: syntax error near `d'
> $ [[ -e "a d e.f" ]] && echo 1
> 1
> 

The [[ ]] and (( )) are the exception to everything else in bash (cd, [, touch, grep). I know of nothing else that acts like it (except array indices).
With all bash commands, the variable is expanded early enough that a space will split the result into multiple parameters (aka word splitting). Ergo these two are the same:
$ cd a b
$ var="a b"; cd $var
cd will see two arguments. Compare to this, which has one parameter:
$ cd "a b"
$ var="a b"; cd "$var"

The same applies to [, which can make stuff fun, eg:
$ [ -n a -a -z a ]               -> returns false because the second condition is false and there is an and (-a)
$ var="a -a -z a"; [ -n $var ]   -> false, too! Go figure...

$ var="a -a -z a"; [ -n "$var" ] -> works right

The [[ and (( are "special". Word splitting will not occur inside. (Array indices are computed in arithmetic mode, ie like inside ((: ${arr[stuff]}).
The entire parsing is set up different. Word splitting does not occur. And (mostly as an aside,) bash parses them over double as fast.

Concatenating variables has no special rules. It acts identical to one variable with both the contents. Assuming there is no whitespace between them, it is just like one variable. Whitespace inside causes word splitting but not in (( and [[.

Once discussing word splitting, this also applies to arrays, specifically in this context:
$ for var in ${arr[@]} ; do

Without quotes, elements with a space will be turned into multiple elements for the loop.

 - Isaac





More information about the pacman-dev mailing list