Um dia desses cheguei ao trabalho e ao abrir o prompt do Cygwin para usar meus aliases não estavam lá. Demorei um tanto para perceber o que ocorria, enquanto procurava uma solução na Internet reparei que várias pessoas tinham muita dificuldade de entender quando e como o Bash executa os scripts iniciais, assim este esclarecimento pode ser útil para várias destas pessoas.
O que é explicado aqui vale para o bash, seja no Cygwin seja no Linux, [1], ou mesmo no OS X [2].
O que se costuma pensar é que quando você entra bash existem dois scripts que são executados, um deles para todos os usuários e outro um para cada usuário. Mas isso não é verdade, ou ao menos é apenas uma pequena parte de verdade. Para entender o que realmente acontece, é preciso entender os vários modos de entrar no bash.
Modos de inicialização de um shell
Existem várias maneiras de se entrar em um shell, ou modos de inicialização. Por exemplo, quando você entra no shell via um login [3], você está num shell de login. Existem coisas que só fazem sentido serem feitas no script de inicialização de um shell se se está fazendo o login.
Quando se entra em um shell sem fazer login [4], você está em um shell de não-login, neste caso nos scripts de inicialização não faz sentido tomar algumas ações que só seriam tomadas no caso de um login.
Para saber de dentro de um shell se ele é de login deve-se testar se a opção do shell chamada login_shell
está setada. As opções de shell podem ser setadas, resetadas e testadas com o comando shopt
, e shopt –q login_shell
, por exemplo, suprime a saída para a tela do comando shopt
e dá um status de retorno 0 se a opção estiver setada e diferente de zero se estiver resetada. Para forçar um script de login (o que é feito no cygwin.bat
), chama-se o bash com uma das seguintes opções: -l
ou –login
.
Existe ainda outra modo de inicialização [5], o shell não iterativo [FSF1], quando temos um script sendo executado por algum processo [6]. Em um shell não interativo não faz sentido ajustar mapeamento de teclas especiais, prompt de comando, etc., já que estas são coisas úteis apenas quando se interage com o shell.
Para saber se o shell em que você se encontra (dentro de um script por exemplo) é interativo ou não, usa-se o parâmetro especial $-
, se ele contiver um i minúsculo significa que ele é interativo. Outra maneira é verificar se existe a variável de ambiente $PS1
se ela não estiver atribuída o shell é não interativo.
Scripts de inicialização
Agora que conhecemos os vários modos de um script podemos entender os scripts de inicialização.
Quando o bash é iniciado em modo interativo e de login, ele executa o script [FSF2] /etc/profile
, este script é executado para todos os usuários. Uma das coisas que este script costuma fazer é executar todos os scripts no diretório /etc/profile.d
, essa organização é melhor pois scripts com finalidades diferentes ficam separados no lugar de se executar um script enorme.
Após isso ele procura os scripts ~/.bash_profile
, ~/.bash_login
e ~/.profile
e executa os comandos do primeiro que encontrar e apenas deste. Como cada arquivo destes está no diretório home do usuário, estes arquivos de inicialização são específicos de cada usuário [FSF3].
Quando o bash é iniciado em modo interativo que é de não-login são executados os scripts /etc/bash.bashrc
(que vale para todos os usuários) e ~/.bashrc
(para cada usuário).
Claro que usuário pode inibir a execução destes scripts, imagine que um amigo deste usuário pegou sua conta aberta no terminal e editou alguns dos scripts de inicialização por usuário colocando como primeiro comando o comando logout
. Como ele faria para fazer login? Se se deseja inibir os profiles de login usa-se a opção –-noprofile
, se forem os scripts de não login existem duas opções, uma delas é –-norc
que inibe a execução dos scripts de inicialização ou –-rcprofile file
que executa o script com o nome file
em vez do script padrão.
Normalmente as coisas colocadas no ~/.bashrc
são desejáveis tanto nos shells de login como nos de não-login, assim evitar repeti-las nos arquivos de inicialização de não login normalmente o que se faz é executar o ~/.bashrc
dentro dos arquivos de inicialização de não-login. Isso pode confundir você se estiver tentando entender o funcionamento dos scripts de inicialização, já que o ~/.bashrc
vai ser executado mesmo em scripts de login.
Vale notar que se algum dos arquivos mencionados não estiver presente não ocorre erro, mas se estiverem e não for possível sua leitura (por exemplo por causa de permissões), ocorrerá um erro.
Processos e subprocessos
Se você definir seus aliases dentro de um script e executá-lo na linha de comando ou dentro de um script chamado na linha de comando vai perceber que se atribuiu uma variável de ambiente, um alias ou mudou de diretório, quando o script retorna é como se nada tivesse acontecido, estas mudanças não são persistidas.
Isso ocorre porque o script é executado em um processo separado (chamado processo filho), para executar o script no mesmo processo, deve-se chamá-lo com o comando source script
, ou . script
, mesmo que seja dentro de um script de inicialização.
No caso de variáveis de ambiente ao criar uma variável assim: variavel=’123’
ela apenas vale para o shell corrente. Se ela for criada com export variável=’123’
ou for dado export
depois de criada: export variavel
, a variável valerá para todos os processos filhos, mas se for criada e exportada em um processo filho ela não será vista do processo pai (inclusive se houver um variável criada e exportada com este mesmo nome no processo pai seu valor, mesmo que modificado no processo filho não o será no retorno para o processo pai).
E o meu problema no Cygwin? O meu problema no Cygwin não tinha nada a ver com isso, mas achei que esta explicação era necessária.
Notas
[1]. O Ubuntu não usa mais o bash como shell primário desde a versão 6.10, usa o dash [WIKI1] [WIKI3]. É interessante ressaltar duas coisas: que apesar de ter sido feito para o Debian foi o Ubuntu que o adotou como shell primário. Quando foi feita a transição vários scripts usados usavam coisas específicas do bash sem declarar (com a famosa linha inicial com o shebang: #!/bin/bash
). Um dos motivos de fazer esta mudança é tornar o boot mais rápido pois o dash é mais leve mas sem perder muitas funcionalidades.
[2]. No Mac OS X, em 2003 [WIKI2] quando saiu o Panther (OS X 10.3) o shell foi mudado para o bash, anteriormente ele era o TC Shell [MIL1].
[3]. Como por exemplo abrindo uma sessão remota via ssh
.
[4]. Como por exemplo abrindo outro shell de dentro de um shell, entrando em outro usuário com su
ou ainda abrindo um shell de dentro da interface gráfica.
[5]. Existem na verdade quatro modos de inicialização do bash: login, interativo, compatível com sh (Bourne shell) e compatível com POSIX. Os modos não são mutuamente exclusivos, pode-se por exemplo estar no modo compatível com o sh, login e interativo ao mesmo tempo [BHW1].
[6]. Como por exemplo um script agendado para execução através do comando cron
, ou dentro da execução de um script, desde que o script tenha sido executado sem o comando .
ou source
.
Referências
[WIKI1]: BASH: Portability. In: Wikipedia. Disponível em: <http://en.wikipedia.org/wiki/Bash#Portability>. Acesso em: 28 ago. 2009.
[WIKI2]: MAC OS X: Versions. In: Wikipedia. Disponível em: <http://en.wikipedia.org/wiki/Mac_OS_X#Versions >. Acesso em: 28 ago. 2009.
[WIKI3]: DEBIAN Almquist shell. In: Wikipedia. Disponível em: <http://en.wikipedia.org/wiki/Debian_Almquist_shell>. Acesso em: 29 ago. 2009.
[MIL1]: MILLER, David. bash on Mac OS X. [s.l.], 2004. Disponível em: <http://www.oreillynet.com/pub/a/mac/2004/02/24/bash.html>. Acesso em: 28 ago. 2009.
[MOR1]: MORALES, Walter. TC Shell. In: Lecture Notes Sobell. Portland, 2004. Disponível em: <http://spot.pcc.edu/~wmorales/cs140u/week_7.htm>. Acesso em: 28 ago. 2009.
[BHW1]: BASH’S behaviour. In: Bash Hackers Wiki. [S.l], [S.d.]. Disponível em: <http://bash-hackers.org/wiki/doku.php/scripting/bashbehaviour>. Acesso em: 29 ago. 2009.
[FSF1]: FREE SOFTWARE FOUNDATION. Interactive Shells. In: Bash Reference Manual. [S.l.], 13 feb. 2009. Disponível em: <http://www.gnu.org/software/bash/manual/bashref.html#Interactive-Shells>. Acesso em: 30 ago. 2009.
[FSF2]: FREE SOFTWARE FOUNDATION. Bash Startup Files. In: Bash Reference Manual. [S.l.], 13 feb. 2009. Disponível em: <http://www.gnu.org/software/bash/manual/bashref.html#Bash-Startup-Files>. Acesso em: 30 ago. 2009.
[FSF3]: FREE SOFTWARE FOUNDATION. Tilde Expansion. In: Bash Reference Manual. [S.l.], 13 feb. 2009. Disponível em: <http://www.gnu.org/software/bash/manual/bashref.html#Tilde-Expansion>. Acesso em: 30 ago. 2009.
Recent Comments