Keywords: Bash builtin | colon command | special builtin
Abstract: This article provides an in-depth exploration of the : (colon) builtin command in GNU Bash, covering its historical origins, functional evolution, and contemporary uses. By analyzing its role as a no-operation command, comparing it with the true command, and detailing key distinctions between POSIX special and regular builtins—including variable persistence and exec compatibility—the paper offers comprehensive technical insights. Code examples illustrate practical applications in scripting, serving as a valuable reference for developers.
Historical Context and Origins
In early Bourne shell environments, the system did not include built-in true and false commands. To address basic logical evaluation needs, developers often aliased true functionality to :, while false might be simulated using expressions like let 0. This design stemmed from the limitations of shell capabilities at the time, particularly in ancient Bourne-derived shells lacking modern conditional operators such as the ! pipeline operator and || list operator. The core purpose of the : command is to serve as a no-operation (no-op) placeholder, ensuring syntactic completeness.
Basic Functions and Syntactic Applications
As a no-op command, : is primarily used in scripts to fill syntactic positions that must be non-empty. A classic example is in if statements, where the then clause requires content but no actual operation is needed. Comments cannot fulfill this role because they are treated as empty during parsing. Here, : provides an ideal solution:
if command; then :; else ...; fi
This code snippet demonstrates how : acts as a valid placeholder for the then clause, allowing conditional branching to proceed normally. Additionally, : can be used to create simple delay loops or insert comment-like separators in linear command sequences, though these uses may be replaced by more efficient methods in modern scripting.
Comparative Analysis with the true Command
In modern POSIX-compliant environments, : and true are generally interchangeable, both defined by the POSIX standard. However, key differences exist, mainly in their builtin classification: : is categorized as a special built-in command, while true is a regular built-in command. This classification leads to the following important distinctions:
- Variable Persistence: Variables set by special builtins persist in the environment after command execution, whereas those set by regular builtins do not. For example, in ksh93:
$ unset x; ( x=hi :; echo "$x" )
hi
$ ( x=hi true; echo "$x" )
$
This example shows that with :, the value hi of variable x remains in the subshell, while with true, it is cleared. Note that shell support for this behavior varies: Zsh ignores this rule, GNU Bash complies only in POSIX compatibility mode, and major POSIX sh-derived shells like dash, ksh93, and mksh strictly implement it.
exec, meaning they can be replaced by external programs for execution. Special builtins have no such requirement; attempting to use exec with : typically fails because no executable named : exists in the system:$ ( exec : )
-bash: exec: :: not found
$ ( exec true )
$
: may execute faster than true, but this is highly implementation-dependent. In practical scripting, this performance difference is usually negligible unless invoked in extremely intensive loops.Modern Applications and Best Practices
Despite its historical roots, : remains valuable in modern script development. Its nature as a special builtin makes it particularly useful in advanced scripts requiring variable persistence. For instance, in complex conditional logic or environment setup scripts, using : ensures that temporary variables are not accidentally lost. Moreover, for scripts prioritizing maximum portability, : offers backward compatibility with ancient shell environments.
However, in most contemporary use cases, true is often preferred for its clearer semantics. Developers should weigh their choices based on specific needs: : is more suitable when variable persistence or highest portability is required, while true may be optimal for code readability and standard compliance. Regardless of the choice, understanding these underlying differences is crucial for writing robust and efficient shell scripts.