A diferença é o escopo e sintaticamente é muito sutil:
$ ./updater
é o equivalente de
$ /bin/bash ./updater
Ele executa o script (se estiver marcado como executável e em um sistema de arquivos montado com a opção exec
- o último formulário funciona mesmo se uma dessas condições não for atendida). Isso significa que ele gera uma nova instância de shell e alimenta o conteúdo do script. Assim, todos os aliases definidos nele são limitados à duração do shell de interpretação, que é somente até o final do script.
$ . updater
$ . ./updater
$ source updater
$ source ./updater
significa tudo a mesma coisa e diz ao shell current para executar o conteúdo desse arquivo como se você o tivesse digitado na linha de comando. Isso significa que quaisquer aliases, funções, variáveis de ambiente, configurações de opção do shell e assim por diante estarão disponíveis no shell posteriormente.
É também por isso que, às vezes, você vê arquivos init de shell ( ~/.bashrc
no caso do Bash) que se parecem com isso:
#!/bin/bash
for n in ~/etc/bash/*; do
. $n
done
em que ~/etc/bash
pode se parecer:
~/etc/bash/
|-- bash.10.env
|-- bash.20.aliases
'-- bash.30.func
(os nomes são bastante autoexplicativos). Sempre que você adicionar alguns arquivos a esse diretório init, tudo o que você precisa fazer para aplicar as alterações é . ~/.bashrc
. Para o qual você pode ter um alias, é claro. Isso também pode ser estendido - por exemplo, tendo uma inicialização especializada dependendo do hostname (ou fase da lua usando pom
de bsg-games).
Uma grande ressalva para essas configurações: certifique-se de tornar os arquivos init "reentrantes", no sentido de que não importa quantas vezes você os usa em um shell - por exemplo variáveis que você queira preservar devem ser definido condicionalmente:
VAR=${VAR:-"value"}
em vez de incondicionalmente:
VAR="value"