The difference is the scope and syntactically is very subtle:
$ ./updater
is the equivalent of
$ /bin/bash ./updater
It runs the script (if it is marked as executable and on a filesystem mounted with the exec
option - the latter form works even if one of these conditions is not met). That means it spawns new shell instance and feeds it content of the script. Thus any aliases defined therein are limited to the duration of the interpreting shell which is only till the end of the script.
$ . updater
$ . ./updater
$ source updater
$ source ./updater
mean all the same and tell the current shell to execute contents of that file as if you typed it on the command line. That means that any aliases, functions, environment variables, shell option settings and so on will be available in the shell afterwards.
That is also why you sometimes see shell init files (~/.bashrc
in the case of Bash) that look like this:
#!/bin/bash
for n in ~/etc/bash/*; do
. $n
done
where ~/etc/bash
can look like:
~/etc/bash/
|-- bash.10.env
|-- bash.20.aliases
`-- bash.30.func
(the names are quite self-explanatory). Whenever you add some files to such init directory, all you need to do to apply the changes is . ~/.bashrc
. For which you can have an alias, of course. This can be also extended - for example by having specialised initialisation depending on the hostname (or phase of moon by using pom
from bsg-games).
One big caveat for these setups: be sure to make the the init files "re-entrant" in the sense it doesn't matter how many times you source them in one shell - for example variables you may want to preserve should be defined conditionally:
VAR=${VAR:-"value"}
instead of unconditionally:
VAR="value"