If I add the colon
(:
) builtin shell command after an assignment, the variable gets assigned to the empty string (""
). Why does it behave like that? I expected it to have no effect.
set -vx
MyVar1='my var 1' : colon comment here # *** !!! This gets assigned to empty string!!!
MyVar2='my var 2' # hash comment here; this is fine
echo "MyVar1 = [$MyVar1]" # EXPECTED: 'my var 1'; ACTUAL: '' (empty string). Why?
echo "MyVar2 = [$MyVar2]" # As expected.
: (a colon)
: [arguments]
Do nothing beyond expanding arguments and performing redirections. The return status is zero.
https://www.gnu.org/software/bash/manual/html_node/Bourne-Shell-Builtins.html
:
is a built-in command which returns successfully (a shorthand version of true
).
When you do a variable assignment on the same line as a command, the assignment is only valid for the duration of the command (this is typically used to run commands with temporary environment variables set).
So when you run:
MyVar1='my var 1' : colon comment here
You are:
:
colon
, comment
and here
(these are dropped by the command)MyVar1='my var 1'
(this has no effect on the command)This behaviour is described in the spec:
A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator.
...
If no command name results, variable assignments shall affect the current execution environment. Otherwise, the variable assignments shall be exported for the execution environment of the command and shall not affect the current execution environment (except for special built-ins).
As pointed out in the comments (thanks!), :
is one of the special built-ins, which means that in a standards-compliant shell, the assignment should affect the current execution environment. By default, Bash doesn't comply with the spec in this sense, although you can make it do so by invoking it as sh
(on systems where it is the default shell) or by using bash --posix
:
$ bash -c 'foo=bar :; echo $foo'
$ sh -c 'foo=bar :; echo $foo'
bar
$ bash --posix -c 'foo=bar :; echo $foo'
bar