Para que serve o [ -n "$PS1" ]
in [ -n "$PS1" ] && source ~/.bash_profile;
? Esta linha está incluída em um repositório.bashrc
dotfiles .
Para que serve o [ -n "$PS1" ]
in [ -n "$PS1" ] && source ~/.bash_profile;
? Esta linha está incluída em um repositório.bashrc
dotfiles .
Isso está verificando se o shell é interativo ou não. Nesse caso, apenas forneça o
~/.bash_profile
arquivo se o shell for interativo.Consulte "Este Shell é interativo?" no manual do bash, que cita esse idioma específico. (Ele também recomenda verificar se o shell é interativo testando se a
$-
variável especial contém oi
caractere, o que é uma abordagem melhor para esse problema.)O que isso faz
Essa é uma maneira generalizada de testar se o shell é interativo. Cuidado que só funciona no bash, não funciona com outros shells. Então está tudo bem (se bobo) para
.bashrc
, mas não funcionaria em.profile
(que é lido por sh, e bash é apenas uma das implementações possíveis de sh, e não a mais comum).Por que funciona (somente no bash!)
Um shell interativo define a variável shell
PS1
para a string de prompt padrão. Portanto, se o shell for interativo,PS1
está definido (a menos que o usuário o.bashrc
tenha removido, o que ainda não pode ter acontecido no topo de.bashrc
, e você pode considerar que é uma coisa boba de se fazer de qualquer maneira).O inverso é verdadeiro no bash: instâncias não interativas do bash não são definidas
PS1
quando são iniciadas. Observe que esse comportamento é específico do bash e é sem dúvida um bug (por quebash -c '… do stuff with $var…'
não funcionaria quandovar
éPS1
?). Mas todas as versões do bash até e incluindo 4.4 (a versão mais recente enquanto escrevo) fazem isso.Muitos sistemas exportam
PS1
para o ambiente. É uma má idéia, porque muitos shells diferentes usam,PS1
mas com uma sintaxe diferente (por exemplo , os escapes do prompt do bash são completamente diferentes dos escapes do prompt do zsh ). Mas é difundido o suficiente para que, na prática, ver quePS1
está definido não seja um indicador confiável de que o shell é interativo. O shell pode ter herdadoPS1
do ambiente.Por que é (mal) usado aqui
.bashrc
é o arquivo que o bash lê na inicialização quando é interativo. Um fato menos conhecido é que o bash também lê.bashrc
um shell de login e a heurística do bash conclui que esta é uma sessão remota (o bash verifica se seu pai érshd
ousshd
). Neste segundo caso, é improvável quePS1
isso seja definido no ambiente, porque nenhum arquivo dot foi executado ainda.No entanto, a maneira como o código usa essas informações é contraproducente.
.bash_profile
nesse shell. Mas.bash_profile
é um script de tempo de login. Ele pode executar alguns programas que devem ser executados apenas uma vez por sessão. Ele pode substituir algumas variáveis de ambiente que o usuário definiu deliberadamente para um valor diferente antes de executar esse shell. A execução.bash_profile
em um shell sem login é disruptiva..bash_profile
. Mas este é o caso em que o carregamento.bash_profile
pode ser útil, porque um shell de login não interativo não carrega automaticamente/etc/profile
e arquivos~/.profile
.Acho que a razão pela qual as pessoas fazem isso é para usuários que fazem login por meio de uma GUI (um caso muito comum) e que colocam suas configurações de variáveis de ambiente em
.bash_profile
vez de.profile
. A maioria dos mecanismos de login da GUI invoca,.profile
mas não.bash_profile
(a leitura.bash_profile
exigiria a execução do bash como parte da inicialização da sessão, em vez de sh). Com essa configuração, ao abrir um terminal, o usuário obterá suas variáveis de ambiente. No entanto, o usuário não obterá suas variáveis de ambiente em aplicativos GUI, o que é uma fonte muito comum de confusão. A solução aqui é usar.profile
em vez de.bash_profile
definir variáveis de ambiente. Adicionar uma ponte entre.bashrc
e.bash_profile
cria mais problemas do que resolve.O que fazer em vez disso
Existe uma maneira simples e portátil de testar se o shell atual é interativo: teste se a opção
-i
está habilitada.Isso é útil
.bashrc
para ler.profile
apenas se o shell não for interativo - ou seja, o oposto do que o código faz! Leia.profile
se o bash for um shell de login (não interativo) e não o leia se for um shell interativo.Parece que esse conceito estranho é resultado do fato de que
bash
não começou como um clone do shell POSIX, mas como umBourne Shell
clone.Como resultado, o comportamento interativo POSIX (
$ENV
é chamado para shells interativos) foi adicionado posteriormentebash
e não é amplamente conhecido.Há um shell que concede um comportamento semelhante. Isso é
csh
e csh grants que$prompt
tem valores específicos:Mas isso não se aplica ao Bourne Shell nem aos shells POSIX.
Para um shell POSIX, o único método concedido é colocar código para shells interativos no arquivo:
que tem um nome específico de shell. É por exemplo
Outras pessoas mencionaram o sinalizador de shell
-i
, mas isso não é útil para programação confiável. O POSIX não requer queset -i
funcione, nem que$-
contenha umi
para shells interativos. POSIX apenas requer que imponhash -i
o shell no modo interativo.Como a variável
$PS1
pode ser importada do ambiente, ela pode ter um valor mesmo no modo não interativo. O fato de quebash
unset
sPS1
em qualquer shell não interativo não é concedido pelo padrão e não é feito por nenhum outro shell.Portanto, programação limpa (mesmo com
bash
) é colocar os comandos para shells interativos em$HOME/.bashrc
.Vou falar primeiro sobre o que o Debian e, na maioria das vezes, também o Ubuntu define para o bash. E último toque em outros sistemas.
Na configuração dos arquivos de inicialização do shell, há muita opinião.
Também tenho minha opinião, mas tentarei mostrar exemplos existentes de configurações corretas.
Vou usar o debuan, pois é bem fácil encontrar exemplos de seus arquivos.
E o debian é muito usado, então as configurações foram bem testadas,
Qual é o objetivo de verificar se o PS1 está definido?
Apenas para descobrir se o shell é interativo.
O padrão
/etc/profile
no debian e no ubuntu (de /usr/share/base-files/profile):O if é lido: se interativo (conjunto padrão do PS1) e é um shell bash (mas não atuando como padrão
sh
), altere o PS1 para um novo específico (não o padrão).O padrão
/etc/bash.bashrc
no debian também contém:O que é bastante claro no que faz: se interativo, não fonte (o resto).
No entanto, in
/etc/skel/.bashrc
é um exemplo da maneira correta de testar um shell interativo (usando$-
):Isso deve mostrar claramente o porquê do PS1 e uma alternativa.
A ordem correta
A configuração que você está relatando deve ser evitada.
A ordem (das configurações do sistema para configurações de usuário mais específicas (para bash)) é
/etc/profile
,/etc/bash.bashrc
e~/.profile
finalmente~/.bashrc
. Isso coloca os efeitos mais amplos (e para mais shells) em/etc/profile
(que é de propriedade do root) seguido por/etc/bash.bashrc
(que também é de propriedade do root), mas afeta apenas o bash. Em seguida, vêm as configurações pessoais em$HOME
, a primeira é~/.profile
para a maioria dos shells e~/.bashrc
(quase equivalente a~/.bash_profile
), específica apenas para o bash.Portanto, é errado originar , está transformando uma configuração de usuário específica para bash em uma mais geral que está
~/.bashrc
afetando mais shells . Exceto se feito desta forma :~/.profile
Ele verifica se o bash está em execução e carrega apenas
.bashrc
se for o caso.Esta é uma decisão upstream vinda do Debian. A razão é explicada aqui .
Na verdade, o inverso, sourcing
~/.profile
em~/.bash_profile
(ou~/.bashrc
) está apenas reaplicando regras gerais que já deveriam ter sido carregadas para um caso de uso específico e, portanto, "não é tão ruim" (não estou dizendo "bom"). E não estou dizendo bem porque isso pode fazer com que a fonte de arquivos entre em loop. Como quando um subdiretório carrega um pai, isso é um loop de diretório.E é nesse cruzamento de fontes que a verificação do shell interativo faz sentido. Somente quando um shell é interativo é
~/.bashrc
carregado, mas por sua vez pode estar carregando~/.profile
(ou vice-versa) e é neste caso que a verificação de um shell interativo pode ser usada.