September 14, 2022

Bash Builtin Colon

: is a shell builtin command inherited from the Bourne Shell. It does nothing beyond expanding arguments and performing redirection and has return status zero. : is a no-op operator similar to true and false. In fact, command true and : both use the same function int colon_builtin() underneath.

Parameter expansions

Shell’s parameter expansions are used to check and modify parameters.

Below illustrated how : is used in parameter expansion by setting a default value combined with :.

$ cat ./colon_script.sh
#!/usr/bin/env bash
read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
$ ./colon_script.sh
Enter your name:
John Doe
$

If : is omitted, the default value is passed and treated as a command.

]$ ./colon_script.sh
Enter your name:
./colon_script.sh: line 3: John: command not found
John Doe

John Doe is still printed as the value has been assigned to variable name.

More on Parameter expansion substitution

Use a default value

${parameter:-word}

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

Example:

#!/usr/bin/env bash

read -p "Enter your address (Press enter to not input address): " address
echo "You address is ${address:-unknown}."

The script will print “You address is unknown.” when enter is pressed and no input is given. The default value is used on expansion time, it is not assigned to the parameter.

Assign a default value

${PARAMETER:=WORD}

If parameter is unset or null, the expansion of word is assigned to parameter. The value of parameter is then substituted. Positional parameters and special parameters may not be assigned to in this way.

Example:

#!/usr/bin/env bash

read -p "Enter your address (Press enter to not input address): " address
echo "You address is ${address:=unknown}."
echo "Checking. You address is really: $address	."

Here the default text is expanded and assigned to the parameter.

Use an alternate value

${parameter:+word}

If parameter is null or unset, nothing is substituted, otherwise the expansion of word is substituted.

This form expands to nothing if the parameter is unset or empty. If it is set, it does not expand to the parameter’s value, but to some text you can specify

Example:

$ cat ./home.sh
#!/usr/bin/env bash

echo "Your home is ${HOME:+ - This text will be printed since $HOME is set}."
$ ./home.sh
Your home is  - This text will be printed since /home/zain is set.

Replace true by :

The usual way to do infinite loop in bash is using the true command in a while loop.

#!/usr/bin/env bash
while true
  do 
    # ...
done

Alternatively, we can use : instead of true to create an infinite loop.

#!/usr/bin/env bash
while : ; do 
   # ....
done

just a : as first line in a shell

I came across a this forum where user smehra were working on porting some shell script to Solaris and stumbled on : as the first line instead of the usual shebang and wanted to know more about it.

User Perderabo introduced a very useful background about the c shell, Bourne shell and comments, which is as follows:

When the Bourne shell was introduced, it did not have any way to handle comments. It did have the : command which does nothing. So people used the : command as a poor man’s comment. Like this:

: This is a comment.

This was better than nothing, but these “comments” have syntax restrictions. And they can have side effects that are persist past the statement.

Then Bill Joy introduced the c shell. It had the # syntax for comments. In these days, the shell had to run shell scripts. The kernel did not yet recognize the “#! /path/to/interpreter”. Bill Joy wanted his shell to be able to run both sh scripts and csh scripts. So he had to tell them apart. His solution was to assume that all scripts will start with a comment. So if the first character was a “:”, it was a sh script. And if the first character was a “#”, it was a csh script.

But then Steve Bourne added in the # syntax to sh. That broke the csh solution. The fix to this problem was to let the kernel handle shell scripts. That is where the “#!” syntax came in.

colon instead of shebang

Using : instead of the shebang works fine.

$ cat ./colon_test.sh
:

echo "Hello World!"

$ ./colon_test.sh
Hello World!

Resources

https://askubuntu.com/questions/549608/what-is-the-point-of-the-bash-null-operator-colon

https://www.unix.com/shell-programming-and-scripting/10193-just-first-line-shell.html

https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html

https://wiki.bash-hackers.org/syntax/pe#use_a_default_value

Powered by Hugo & Kiss.