Estou no Fedora, onde todos os shells pré-instalados aparentemente suportam bashisms: bash --posix
does, e até mesmo sh
. Ainda assim, quando usei esta função ,
pathprepend () {
if [[ ":$PATH:" != *":$1:"* ]]; then
PATH="$1${PATH:+":$PATH"}"
fi
}
para adicionar um diretório a PATH
partir de ~/.profile
, o Git não o pegou. Note que echo $PATH
na sessão bash da qual eu estava usando o Git listou meu diretório, notei que só porque eu uso diff-highlight
, symlinked naquele diretório, e depois que comecei a usar a pathprepend
função acima o Git reclamou que diff-highlight
estava faltando. Depois de restaurar uma PATH
configuração compatível com POSIX, ele voltou a funcionar normalmente.
Isso me deixou pensando o que os programas usam para ler seu ambiente. Cada um deles vem com seu próprio mecanismo para fazer isso? Eles deixam o trabalho para algum shell ou biblioteca do sistema?
Editar
@Bodo, é isso que eu costumava fazer: em ~/.profile
,
pathprepend () {
if [[ ":$PATH:" != *":$1:"* ]]; then
PATH="$1${PATH:+":$PATH"}"
fi
}
pathprepend "$HOME/.local/bin"
Por "compatível com POSIX" quero dizer sem nenhuma bashism. Isto é o que tenho agora em ~/.profile
:
pathprepend () {
case ":$PATH:" in
*":$1:"*)
:;;
*)
PATH="$1${PATH:+":$PATH"}";;
esac
}
pathprepend "$HOME/.local/bin"
Em ambos os casos ~/.profile
é proveniente de ~/.bash_profile
, que contém
# Load the configuration for login sessions of any shell
if [[ -f "$HOME/.profile" ]]; then
source "$HOME/.profile"
else
echo >&2 "$HOME/.bash_profile: $HOME/.profile not found"
fi
# Load the configuration for interactive non-login Bash sessions
case "$-" in *i*)
if [[ -f "$HOME/.bashrc" ]]; then
source "$HOME/.bashrc"
else
echo >&2 "$HOME/.bash_profile: $HOME/.bashrc not found"
fi;;
esac
Não fiz isso export
PATH
porque Gordon Davisson explica na resposta da qual copiei a função que " PATH
já deveria estar marcado como exportado, então não é necessário reexportar". Na verdade, ainda não fiz, export
mas com a case
versão de pathprepend
tudo funciona bem. A propósito, qual é o processo pai do processo Git, é o processo Bash do qual eu uso git
?
os programas obtêm seu ambiente do terceiro argumento da
execve(program_path, argv, envp)
chamada de sistema que os executou.envp
, comoargv
é uma matriz de strings, exceto queenvp
, por convenção, as strings estão novar=value
formato .O que os programas fazem com essas strings depende deles, mas geralmente eles pegam essas
var=value
strings e interpretam o que está à esquerda da primeira=
como o nome de uma variável de ambiente e o que está à direita como seu valor.Eles geralmente armazenam essa lista de lado e quando eles, no mesmo processo ou em um processo filho, executam outros comandos, eles passam essa mesma lista no terceiro argumento para a
execve()
chamada de sistema correspondente.A biblioteca C tem ajudantes para isso. Essa lista armazenada à parte é a
environ
variável ali, e as funçõesputenv()
/setenv()
/unsetenv()
podem ser usadas para adicionar/modificar/remover variáveis ali e funções comoexeclp()
são wrappers para aexecve()
chamada do sistema que passam issoenviron
adiante automaticamente comoenvp
. A ideia é que o ambiente seja algo que seja herdado automaticamente durante a execução¹.A maioria dos shells mapeia variáveis de ambiente para variáveis de shell.
Em shells do tipo POSIX, variáveis que
envp
têm um nome compatível com o de uma variável de shell são convertidas em uma variável de shell que é marcada com oexport
atributo . E oexport
utilitário especial embutido pode ser usado para promover uma variável de shell para uma variável de ambiente para que ela seja passada emenvp
cada comando executado depois disso.~/.profile
é um arquivo de inicialização de sessão que é interpretado pela maioria dos shells do tipo Bourne quando são invocados como shells de login (o quelogin
é feito adicionando um-
aargv[0]
). O equivalente para shells do tipo csh seria~/.login
, veja também~/.zprofile
/~/.zlogin
para zsh.Hoje em dia, isso normalmente é lido ao efetuar login
ssh
(ssh host
somente norlogin
modo , nãossh host 'shell code'
norsh
modo que não efetua login) ou em um terminal virtual ousudo -i
, raramente por emuladores de terminal iniciados dentro de uma sessão de login gráfico.Alguns ambientes gráficos tentam iniciar o shell de login do usuário como invocações de shell de login não interativas que interpretam esses arquivos de ambiente de sessão no login em uma tentativa de obter as mesmas variáveis de ambiente lá, mas não todas. Outros mecanismos são às vezes usados lá para definir variáveis de ambiente.
Se, ao efetuar login, seu shell de login foi iniciado como um shell de login e é do tipo Bourne (e não zsh), ele terá interpretado o código em
~/.profile
.Ao interpretar,
PATH="~/.local/bin${PATH:+":$PATH"}"
ele terá atualizado a variável$PATH
do shell . Como essa variável terá sido encontrada noenvp
que foi passado para esse shell, essa variável será marcada paraexport
e a variável com seu valor modificado² será incluída noenvp
passado para cada comando executado depois disso, incluindogit
. Segit
fizer umgetenv("PATH")
, ele deve obter esse valor modificado.Mas para que isso aconteça, o
~/.profile
deve ter sido interpretado por um shell na ancestralidade do processo que o executougit
.¹ Não deve ser confundido com o relacionamento pai/filho. Um filho herda tudo de seu pai, mas a execução apaga toda a memória e é onde você precisa de um mecanismo como o ambiente para passar informações.
² Exceto no Bourne shell, onde a modificação da variável do shell não é refletida na variável de ambiente, a menos que você chame
export
. Mas você não encontrará o Bourne shell no Fedora nem em nenhum sistema moderno.