Respostas:
Isso está verificando se o shell é interativo ou não. Nesse caso, apenas procure o ~/.bash_profile
arquivo se o shell for interativo.
Consulte "Este shell é interativo?" no manual do bash, que cita esse idioma específico. (Também recomenda verificar se o shell é interativo, testando se a $-
variável especial contém o i
caractere, o que é uma abordagem melhor para esse problema.)
bash
desativa o PS1 quando não interativo (erro de digitação no seu comentário anterior) é um bug da IMO, o PS1 não é uma variável específica do bash, não há negócios em desabilitá-lo. É o único shell que faz isso (embora yash
também seja definido PS1
como um valor padrão mesmo quando não interativo).
[[ $- = *i* ]] && source ~/.bash_profile
).
[ -n "${PS1}" ]
, mas ainda atualizei minha resposta para destacar que o manual do bash também sugere / recomenda a inspeção $-
para determinar se o shell é interativo, espero que você ache que melhora a resposta. Felicidades!
Essa é uma maneira generalizada de testar se o shell é interativo. Cuidado que ele só funciona no bash, não funciona com outras conchas. Portanto, está tudo bem (se for bobo) .bashrc
, mas não funcionaria .profile
(o que é lido por sh, e o bash é apenas uma das implementações possíveis do sh, e não a mais comum).
Um shell interativo define a variávelPS1
do shell como a sequência de prompt padrão. Portanto, se o shell é interativo, PS1
está definido (a menos que o usuário o .bashrc
tenha removido, o que ainda não pode ter acontecido no topo .bashrc
, e você pode considerar que é uma coisa boba de se fazer).
O inverso é verdadeiro no bash: instâncias não interativas do bash desativadas PS1
quando iniciadas. Observe que esse comportamento é específico do bash e é sem dúvida um bug (por que bash -c '… do stuff with $var…'
não funcionaria quando var
é PS1
?). Mas todas as versões do bash até o 4.4 (inclusive a versão mais recente que eu escrevo) fazem isso.
Muitos sistemas exportam PS1
para o meio ambiente. É uma má idéia, porque muitos shells diferentes usam, PS1
mas com uma sintaxe diferente (por exemplo , escapes de prompt do bash são completamente diferentes dos escapes de prompt do zsh ). Mas é bastante difundido que, na prática, ver o que PS1
está definido não é um indicador confiável de que o shell seja interativo. O shell pode ter herdado PS1
do ambiente.
.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 logon e as heurísticas do bash concluem que esta é uma sessão remota (o bash verifica se seu pai é rshd
ou sshd
). Nesse segundo caso, é improvável que PS1
isso seja definido no ambiente, porque nenhum arquivo de ponto 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. Pode executar alguns programas que devem ser executados apenas uma vez por sessão. 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 logon é perturbadora..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 /etc/profile
e automaticamente ~/.profile
.Eu acho que a razão pela qual as pessoas fazem isso é para usuários que efetuam login através 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 é chamada, .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, quando o usuário abre um terminal, ele obtém suas variáveis de ambiente. No entanto, o usuário não obterá suas variáveis de ambiente nos aplicativos GUI, o que é uma fonte muito comum de confusão. A solução aqui é usar em .profile
vez de .bash_profile
definir variáveis de ambiente. Adicionar uma ponte entre .bashrc
e .bash_profile
cria mais problemas do que resolve.
Existe uma maneira simples e portátil de testar se o shell atual é interativo: teste se a opção -i
está ativada.
case $- in
*i*) echo "This shell is interactive";;
*) echo "This shell is not interactive";;
esac
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 é um shell de logon (não interativo) e não o leia se for um shell interativo.
if [[ $- != *i* && -r ~/.profile ]]; then . ~/.profile; fi
[[ -o interactive ]]
(ksh, bash, zsh) ou case $- in (*i*) ...; esac
(POSIX)
PS1
se não for executado de forma interativa. É fácil testar: PS1=cuckoo bash -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
não imprime nada, enquanto PS1=cuckoo bash -i -c '[ -n "${PS1}" ] && echo "PS1=[${PS1}]"'
imprime o valor $PS1
definido nos arquivos de inicialização do bash (não imprime a string "cuckoo").
$-
contenha i
um shell interativo.
[ -n "${PS1}" ]
errado está indo um pouco longe demais, afinal só quebra quando alguém está exportando o PS1 (que na sua resposta você diz que é uma péssima idéia e até explica as razões) e isso não afeta bash de qualquer maneira (já que desabilita o PS1 e o PS2 se o shell não for interativo.) Talvez usar uma palavra como "desanimado" ou falar sobre as "limitações" da abordagem fosse melhor. Eu não acho que esteja "errado" por completo. Se algo estiver errado na exportação do PS1, com certeza! De qualquer forma, obrigado por entrar em detalhes.
Parece que esse conceito estranho é resultado do fato de bash
não ter começado como um clone do shell POSIX, mas como um Bourne Shell
clone.
Como resultado, o comportamento interativo do POSIX ( $ENV
chamado de shells interativos) foi adicionado posteriormente bash
e não é amplamente conhecido.
Há um shell que concede comportamento semelhante. São csh
concessões e csh que $prompt
possuem valores específicos:
$prompt not set non-interactive shell, test $?prompt.
$prompt set but == "" .cshrc called by the which(1) command.
$prompt set and != "" normal interactive shell.
Mas isso não se aplica ao shell Bourne nem aos shells POSIX.
Para um shell POSIX, o único método concedido é colocar código para shells interativos no arquivo:
$ENV
que tem um nome específico do shell. É por exemplo
$HOME/.kshrc for the korn shell
$HOME/.bashrc for bash
$HOME/.mkshrc for mksh
$HOME/.shrc for the POSIX Bourne Shell
Outras pessoas mencionaram o sinalizador de shell -i
, mas isso não é utilizável para programação confiável. O POSIX não exige que set -i
funcione nem que $-
contenha um i
para shells interativos. O POSIX exige apenas que imponha sh -i
o shell ao 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 que bash
unset
s PS1
em qualquer shell não interativo não é concedido pelo padrão e não é feito por qualquer outro shell.
Portanto, a programação limpa (mesmo com bash
) é colocar os comandos para shells interativos $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 início do shell, há muita opinião.
Eu também tenho minha opinião, mas tentarei mostrar exemplos existentes de configurações corretas.
Vou usar o debuan, pois é muito fácil encontrar exemplos de seus arquivos.
E o debian é muito usado, então as configurações foram bem testadas,
Apenas para descobrir se o shell é interativo.
O padrão /etc/profile
no debian e no ubuntu (de / usr / share / arquivos-base / perfil):
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
O if é lido: se interativo (conjunto padrão do PS1) e é um shell bash (mas não atua como padrão sh
), altere o PS1 para um novo em particular (não o padrão).
O padrão /etc/bash.bashrc
no debian também contém:
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
O que é bastante claro no que faz: se interativo, não faça a fonte (o resto).
No entanto, em /etc/skel/.bashrc
é um exemplo da forma correcta de teste para uma concha interactivo (utilizando $-
):
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
Isso deve mostrar claramente o porquê do PS1 e uma alternativa.
A configuração que você está relatando deve ser evitada.
A ordem (de configurações do sistema para mais definições específicas do usuário (para bash)) é /etc/profile
, /etc/bash.bashrc
, ~/.profile
e, finalmente ~/.bashrc
. Isso coloca os efeitos mais amplos (e para mais shells) em /etc/profile
(que pertence à raiz), seguido por /etc/bash.bashrc
(que também pertence à raiz), mas afeta apenas o bash. Em seguida, entram as configurações pessoais $HOME
, a primeira é ~/.profile
para a maioria das conchas e ~/.bashrc
(quase equivalente a ~/.bash_profile
), específica apenas para o bash.
Por isso, é errada a fonte ~/.bashrc
em ~/.profile
, ele está transformando uma configuração para a festança de uma forma mais geral que é usuário específico afetando mais conchas . Exceto se feito desta maneira :
# ~/.profile: executed by the command interpreter for login shells
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
Ele verifica se o bash está em execução e só carrega .bashrc
se for esse o caso.
Esta é uma decisão upstream vinda do Debian. A lógica é explicada aqui .
Na verdade, o inverso, o abastecimento ~/.profile
em ~/.bash_profile
(ou ~/.bashrc
) só é re-aplicação de regras gerais que devem ter sido já carregados para um caso de uso particular, e, portanto, "não é tão ruim" (não estou dizendo "bom"). E não estou dizendo bom, porque isso pode causar um loop no fornecimento de arquivos. Como quando um subdiretório carrega um pai, isso é um loop de diretório.
E é nessa fonte cruzada que a verificação do shell interativo faz sentido. Somente quando um shell é interativo é ~/.bashrc
carregado, mas por sua vez, ele pode estar carregando ~/.profile
(ou vice-versa) e é nesse caso que a verificação de um shell interativo pode ser usada.
( export PS1='abc$ '; bash -c 'echo "[$PS1]"' )
, o que simplesmente imprime[]
. Parece que o zsh não faz o mesmo, pelo menos a partir de um experimento ... De qualquer forma, a intenção do[ -n "$PS1" ]
é verificar se o shell é interativo ou não.