Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I read the following in A User's Guide to the Z-Shell:

A synonym for ‘true’ is ‘:’; it’s often used in this form to give arguments which have side effects but which shouldn’t be used — something like

: ${param:=value}

which is a common idiom in all Bourne shell derivatives. In the parameter expansion, $param is given the value value if it was empty before, and left alone otherwise. Since that was the only reason for the parameter expansion, you use : to ignore the argument. Actually, the shell blithely builds the command line — the colon, followed by whatever the value of $param is, whether or not the assignment happened — then executes the command; it just so happens that ‘:’ takes no notice of the arguments it was given.

but I don't understand it. I get that : means true, but there are two colons in the expression. As a minor question, why is this idiom used so much in all Bourne shell derivatives? What purpose does it serve?

Note: I am interested in what this idiom does in both bash and in zsh.

Thanks

share|improve this question
    
Are you asking for zsh or bash? –  enzotib Nov 26 '11 at 22:12
    
@enzotib, I'm interested in both. I clarified that. –  user815423426 Nov 26 '11 at 22:15

3 Answers 3

up vote 7 down vote accepted

Let's break this down into pieces.

This code runs the command : with some arguments. The command : does nothing and ignores its arguments. Therefore the whole command line does nothing, except whatever side effects happen in the arguments.

The syntax ${parameter_name:=value} exists in all non-antique Bourne-style shells, including ash, bash, ksh and zsh. It sets the parameter to a default if necessary. It is equivalent to

if [ -z "$parameter_name" ]; then parameter_name=value; fi
… ${parameter_name}

In other words, if parameter_name is not set or is set to an empty value, then set it to the indicated value; and then run the command, using the new parameter value. There is a variant, ${parameter_name=value}, which leaves the parameter empty if it was empty, only using the indicated value if the parameter was unset.

You'll find this syntax documented under “parameter expansion” in the POSIX spec, and the dash, bash, ksh and zsh manuals.

There are variations on this syntax, in particular ${parameter_name:-value} which let you use a default value for this expansion only, without assigning to the parameter.

In summary, : ${parameter_name:=value} is a concise way of writing

if [ -z "$parameter_name" ]; then parameter_name=value; fi
share|improve this answer

: does not mean true -- you're probably thinking of while :, but even in that expression it doesn't mean "true", it merely happens evaluate to it (in fact, it is simply a null command, or noop).

This parameter expansion (${x:=y}) means "assign y to x if x is unset or empty, and expand to y".

$ echo "${foo:=bar}"
bar
$ foo=baz
$ echo "${foo:=bar}"
baz
$ foo=
$ echo "${foo:=bar}"
bar
$ echo "${foo}"
bar

The Bash Hackers wiki has a good article on parameter expansion here.

The reason that : is used is so that whilst other parts of the command are evaluated, they are not acted upon (as : is a null command). Thus, you have ${x:=y} perform its function without affecting anything else, for example, if you didn't have the : at the beginning, it would try to execute a command called y.

Here is bash's help page on ::

:: :
    Null command.

    No effect; the command does nothing.

    Exit Status:
    Always succeeds.
share|improve this answer

The first : is a command, it's called a "noop" or "no operation". As said in the manpage, it is often used to evaluate the arguments.

The second : is a qualifier in the variable expansion - technically it is :=. Which as said, this sets the value if it does not have a value.

Idiom-wise, if you need a default value of an environment variable, then you can use this syntax. For example, when running a program through cron(8), the environment is not set and and the shell's dot files are not run. So you may need to set some defaults.

: ${JAVA_HOME:=/usr/local/jdk-1.6.0_28}

Then you can 'set it and forget it' (until the default jvm changes).

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.