Onde devo exportar uma variável de ambiente para que todas as combinações de bash / dash, interativo / não interativo, logon / não logon possam buscá-la?

11

Aqui está a motivação para a pergunta:

Estou usando o Ubuntu 12.04 LTS 2 com a área de trabalho do Unity. No meu arquivo .bashrc, anexo vários diretórios à minha variável PATH e defino algumas variáveis ​​de ambiente, como JAVA_HOME. Quando inicio aplicativos a partir de um terminal (executando bash, meu shell padrão), isso funciona muito bem, mas para vários dos atalhos que usam o iniciador do Unity, eles executam aplicativos que parecem definidos para usar #! / Bin / sh, que é um alias para / bin / dash e eles não capturam o conteúdo de ~ / .bashrc ou ~ / .profile.

Suponho que eu poderia alterar todos esses atalhos para usar / bin / bash em vez de / bin / sh para forçá-lo a pegar as alterações .bashrc, mas isso parece realmente hacky.

Dado que o Ubuntu 12.04 (por padrão) aliases / bin / sh para / bin / dash e que meu shell padrão é / bin / bash, existe um único local onde eu posso escolher modificar o PATH e definir variáveis ​​de ambiente, se eu quiser estar presente em todas essas circunstâncias:

  1. Sempre que eu crio um shell bash sem login (usando o terminal em unidade)
  2. Sempre que eu crio um shell bash de login (por exemplo, efetuando login remotamente pelo ssh)
  3. Sempre que uso um iniciador de aplicativos Unity (dado que o iniciador usa / bin / sh).
  4. Sempre que um trabalho cron é executado (considerando que SHELL = / bin / sh em / etc / crontab).

Se entendi direito, acho que:

  • (1) / (2) e (3) / (4) são diferentes porque (1) / (2) são bash e (3) / (4) são hífen.
  • (1) e (2) são diferentes porque os arquivos que o bash escolhe carregar diferem dependendo se é ou não um shell de login.
  • (3) e (4) são diferentes porque (3) chegará em algum momento após o login (e, portanto, ~ / .profile será originado por um de seus processos pai, enquanto (4) ocorrerá em algum momento ponto em que estou não logado, e, portanto, ~ / .profile não foram lidas.

(Eu não ficaria surpreso se outros fatores também importassem, como se o shell é ou não interativo, então provavelmente há mais combinações que eu nem imaginava ... Estou feliz por ter minha pergunta "melhorada " nesse caso.)

Eu esperaria que, em algum momento, alguém devesse ter feito algum tipo de guia que informa como / onde modificar variáveis ​​de ambiente de maneira independente do shell (ou pelo menos de uma maneira compatível com dash / bash) ... Eu simplesmente posso ' parece que não encontrou os termos de pesquisa corretos para localizar esse guia.

Soluções ou indicadores para soluções muito apreciadas!

Atualizada:

  • Esclarecimento: Este é o usuário padrão do Ubuntu criado pelo processo de instalação da 12.04, portanto, nada de especial. Ele não tem um ~ / .profile (que explicitamente fontes ~ / .bashrc), ea única ~ / .bash * arquivos presentes são .bashrc, .bash_history e .bash_logout ... por isso não há nenhuma .bash_profile.
  • Ênfase no escopo: eu realmente não me importo com outros shells que não sejam o shell interativo padrão (bash) e qualquer script que use / bin / sh (alias ao dash); portanto, não há necessidade de complicar isso com algo extra para tcsh / ksh / zsh / etc. Apoio, suporte.
Mickalot
fonte
2
Coloque-o em um arquivo e deixe que outros arquivos rc o obtenham.
precisa saber é o seguinte
De acordo com a página de manual do dash, aqui devo ler $ HOME / .profile para shells de login.
Etan Reisner 23/08
@konsolebox Quais arquivos rc? AFAICT, dash não tem um arquivo rc. E, como afirmei, o dash não parece estar captando o conteúdo do ~ / .profile.
@EtanReisner Sim, e esse é o ponto da questão. Quando o dash não está sendo executado como um shell de logon (e, portanto, ~ / .profile não é originado), o que acontece então?
@Mickalot Você está executando o dash interativamente? Caso contrário, tente adicionar a opção -l.
precisa saber é o seguinte

Respostas:

9

A invocação de shell é um pouco complicada. As páginas de manual bash e dash têm INVOCATIONseções sobre isso.

Em resumo, eles dizem (há mais detalhes na página de manual, você deve lê-lo):

When bash is                   | it reads
-------------------------------|----------
login shell                    | /etc/profile and then the first of ~/.bash_profile, ~/.bash_login or ~/.profile that exists.
                               |
interactive non-login shell    | /etc/bash.bashrc then ~/.bashrc
                               |
non-interactive shell          | The contents of $BASH_ENV (if it exists)
                               |
interactive (as "sh")          | The contents of $ENV (if it exists)

-

When dash is                   | it reads
-------------------------------|---------
login shell                    | /etc/profile then .profile
                               |
interactive shell              | The contents of ENV (it it exists, can be set in .profile as well as in initial environment)

Não conheço outras conchas de imediato, pois nunca as uso. Sua melhor aposta pode ser definir algumas variáveis ​​de ambiente para apontar para o script de localização comum e originar manualmente (quando apropriado) nos dois casos que não abrangem.

Etan Reisner
fonte
Infelizmente, o ponto crucial desse problema é o que está faltando na sua tabela de traços. Quando a área de trabalho do Unity chama qualquer script que comece com #! / Bin / sh, ele lança (o que eu assumo é) um shell de traço sem login e não interativo. Então a questão é: como faço para fazer as mesmas variáveis de ambiente disponíveis que estão presentes em toda a parte na matriz?
Direita. Eu imagino que é por isso que o bash adicionou BASH_ENV para esse slot. Dado que o traço não parece ter nada que funcione nesse slot, não tenho certeza de que você possa resolver esse problema sem afetar a alteração no ambiente do aplicativo que inicia o traço (como o traço o herda). Isso exigiria que as variáveis ​​de ambiente estivessem definidas no seu ambiente X, e é aí que o comentário .xsession (rc) do @Mickalot entra em ação. Isso ainda deixa, como ele indicou, o item quatro deixado de fora (mas acredito que isso é realmente um pouco intencional).
Etan Reisner 23/08
Como estou no Ubuntu 12.04 LTS, o cron é na verdade pixie-cron, para que eu possa definir variáveis ​​env no meu arquivo crontab ... Suponho que SHELL = / bin / bash e BASH_ENV = ~ / .bashrc devem fazer isso?
3

Portanto, existem várias maneiras de abordar isso. Muitas pessoas irão:

uma. Tenha um arquivo que tenha coisas comuns a todas as suas conchas no estilo sh, digamos .shcommone em cada um dos .profile .bashrc .kshrcet cetra, apenas forneça. .shcommon

b. Coloque tudo .profilee proceda da origem dos outros arquivos.

O que é necessário para shells específicos ou shells interativos vs não interativos pode ir no arquivo apropriado antes da fonte .shcommon

Pessoalmente, não gosto de gerenciar vários arquivos. Então, eu uso a seguinte abordagem:

Primeiro, tudo o que preciso é necessário. .profile Como eu tenho algumas coisas específicas do bash e do ksh, eu determino o nome atual do shell usando o seguinte:

# get name of current shell
# strip leading - from login shell
export SHELLNAME="${0#-}"

e, em seguida, tenha comandos para shells específicos em algo como o seguinte (alguns preferem uma declaração de caso).

if [ "$SHELLNAME" = 'bash' ]
then
    shopt -s checkwinsize

elif [ "$SHELLNAME" = 'ksh' ]
then
    stty erase ^?
fi

Se eu tiver comandos que devem ser executados apenas em shells interativos, use o seguinte:

# check for interactive flag i in shell options $-
# in bash and ksh you could use the following, but breaks in dash
# if [[ $- == *i* ]]
if [ "$(echo $- | grep i)" != "" ]
then
  fortune
fi

Coisas que são comuns em todas as conchas no estilo sh, por exemplo, PATHpodem simplesmente ir ao topo.

Em seguida, uso links simbólicos para carregar esse mesmo arquivo em todos os shells do estilo sh:

ln -s .profile .bashrc
ln -s .profile .kshrc

Algumas notas secundárias, se você tiver um .bash_profile, o bash carregará isso em vez de, .profilemas o dash e o ksh ainda carregarão. .profile Isso pode ser parte do seu problema.

Além disso, você pode considerar usar #!/bin/bashseus scripts em vez de, a #!/bin/dashmenos que realmente queira scripts compatíveis com POSIX. O bash possui muitos recursos extras muito agradáveis ​​e o dash ou o bash são chamados, pois o sh desativará muitos desses recursos.

Além disso, a página de manual do bash explica bem quando o .profileversus .bashrcé carregado. Regras semelhantes se aplicam ao ksh. o dash é carregado .profileno logon e permite que você carregue um arquivo na inicialização de shells interativos especificados usando a ENVvariável de ambiente .profile(verifique a página de manual do dash também e pesquise .profile).


fonte
Você não pode apenas testar $ 0 para o nome do shell? Existem conchas / casos em que isso não funciona?
Etan Reisner 23/08
Da mesma forma, a verificação de i em $ - não é suficiente para o teste de shell interativo? (Ele irá desencadear em escudos interativos sem um tty I conceder, mas que pode ou não pode ser um efeito colateral indesejável.)
Etan Reisner
@Etan: Hrm, eu sei que tentei $0e tive problemas ... Não consigo lembrar exatamente o que eram. O login diretamente no console é exibido $0como em -bashvez de, bashmas isso pode ser remediado.
@ Etan: Sim, a verificação de i in $-também funcionaria. Eu teria que pensar em quando você teria um shell interativo sem um tty? Sua solução tem uma "sensação" melhor por algum motivo, posso mudar isso.
O -in -bashsignifica "shell de login", mas sim, você precisaria dar conta disso nos locais em que testar o valor ou desejar exibi-lo para alguém.
Etan Reisner 23/08
0

Como os casos (1) e (2) são resolvidos, fornecendo minhas variáveis ​​de ambiente em .bashrc e .profile, a verdadeira questão é "qual é o nome do arquivo no qual eu origino essas mesmas variáveis ​​para (3) e (4).

Parece que há uma resposta para a parte (3) da pergunta (como faço para que a variável de ambiente seja importada na área de trabalho do Unity) no askubuntu . A sugestão é criar um arquivo ~ / .xsessionrc que será originado por / etc / X11 / Xsession. (Eu tentei isso, e parece funcionar ... yay!)

Ainda estou perplexo com o que fazer (4). Certamente, se eu criar um trabalho cron (ou daemon), posso substituir '/ bin / foo' por algo como 'bash -i -c / bin / foo' para forçá-lo a usar o bash para carregar as variáveis ​​de ambiente corretas, mas isso também significa que terei que mexer com quaisquer ferramentas de terceiros que possam instalar tarefas daemon ou tarefas cron em meu nome. Yuk.

Mickalot
fonte