Onde devo exportar uma variável de ambiente para que todas as combinações de bash / dash, interativas / não interativas, login / não-login, o captem?

10

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, adiciono vários diretórios à minha variável PATH e defino algumas variáveis de ambiente, como JAVA_HOME. Quando eu lanço aplicativos de um terminal (executando o bash, meu shell padrão), isso funciona muito bem, mas para vários dos atalhos que usam o iniciador Unity, eles executam aplicativos que parecem ser definidos para usar #! / Bin / sh, que é aliased para / bin / dash, e eles não pegam o conteúdo de ~ / .bashrc ou ~ / .profile.

Eu suponho que eu poderia mudar todos esses atalhos para usar / bin / bash ao invés de / bin / sh para forçá-lo a pegar as mudanças .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 lugar onde eu posso escolher modificar o PATH e definir variáveis de ambiente se Eu quero que eles estejam presentes em todas destas circunstâncias:

  1. Sempre que eu criar um shell bash sem login (usando o terminal em unidade)
  2. Sempre que eu criar um shell bash de login (por exemplo, efetuar login remotamente por ssh)
  3. Sempre que eu uso um ativador de aplicativo Unity (dado que o ativador usa / bin / sh).
  4. Sempre que uma tarefa do cron for executada (dado que SHELL = / bin / sh no / etc / crontab).

Se eu entendi corretamente, estou supondo que:

  • (1) / (2) e (3) / (4) são diferentes porque (1) / (2) são bash e (3) / (4) são traço.
  • (1) e (2) são diferentes porque os arquivos que o bash escolhe para carregar diferem dependendo se é ou não um shell de login.
  • (3) e (4) são diferentes porque (3) virá em algum ponto após Eu fiz o login (e, portanto, ~ / .profile terá sido originado por um de seus pais processos, enquanto (4) virá em algum momento quando eu não estiver logado e, portanto, ~ / .profile não terá sido lido.

(Eu não ficaria surpreso se outros fatores também importassem, como se a casca é ou não interativa, então provavelmente há mais combinações que eu nem esperei ... Eu estou feliz de ter minha pergunta "melhorada" nesse caso.)

Eu esperaria que em algum momento, alguém deve ter feito algum tipo de guia que lhe diga como / onde modificar variáveis de ambiente de uma maneira independente da shell (ou pelo menos uma forma compatível com traço / bash) ... I simplesmente não consigo encontrar os termos de pesquisa certos para localizar esse guia.

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

Atualizado:

  • Esclarecimento: Este é o usuário padrão do Ubuntu criado pelo processo de instalação do 12.04, então nada sofisticado. Ele tem um ~ / .profile (que explicitamente origina ~ / .bashrc), e os únicos arquivos ~ / .bash * presentes são .bashrc, .bash_history e .bash_logout ... então não não há .bash_profile.
  • Ênfase no escopo: Eu realmente não me preocupo com nenhum shells além do shell interativo padrão (bash) e qualquer script que use / bin / sh (aliased to dash), então não há necessidade de complicar isso com qualquer coisa extra para tcsh / ksh / zsh / etc. suporte.
por Mickalot 23.08.2013 / 20:55

3 respostas

9

A invocação do shell é um pouco complicada. As páginas man do bash e do traço têm INVOCATION seções sobre isso.

Em resumo, eles dizem (há mais detalhes na página man, você deve ler):

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)

Eu não sei sobre outros shells de improviso, pois nunca uso nenhum deles. Sua melhor aposta pode ser definir algumas variáveis de ambiente para apontar para o script de localização comum e fornecer manualmente isso (quando apropriado) nos dois casos que não cobrem.

    
por 23.08.2013 / 21:45
3

Existem várias maneiras de abordar isso. Muitas pessoas irão:

a. Tenha um arquivo com coisas comuns a todos os shells sh-style, digamos .shcommon e em cada um dos .profile .bashrc .kshrc et cetra, apenas forneça isso com . .shcommon

b. Coloque tudo em .profile e coloque isso em outros arquivos.

As coisas que são necessárias para shells específicos ou para shells interativas e não interativas podem então ir para o arquivo apropriado antes de obter .shcommon

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

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

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

e, em seguida, tem 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 só devem ser executados 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 todos os shells sh-style, por exemplo, PATH podem ir no topo.

Então, eu uso links simbólicos para carregar este mesmo arquivo em todos os shells sh-style:

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

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

Além disso, você pode querer considerar o uso de #!/bin/bash em seus scripts, em vez de #!/bin/dash , a menos que você realmente queira scripts compatíveis com POSIX. O bash tem muitos recursos extras que são muito bons e dash ou bash invocados, pois sh desativará muitos desses recursos.

Além disso, a página man bash faz um bom trabalho ao explicar quando .profile versus .bashrc é carregado. Regras semelhantes se aplicam ao ksh. O dash carrega .profile no login e permite que você carregue um arquivo na inicialização de shells interativos que é especificado usando a variável de ambiente ENV em .profile (verifique também a página do manual do traço e procure por .profile). p>     

por 23.08.2013 / 21:38
0

Como os casos (1) e (2) são resolvidos pelo fornecimento de minhas variáveis de ambiente em .bashrc e .profile, a questão real é "qual é o nome do arquivo onde eu forneço essas mesmas variáveis para (3) e (4) ).

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

Ainda estou perplexo com o que fazer (4). Certamente, se eu criar um cron job (ou daemon), eu 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 em quaisquer ferramentas de terceiros que possam instalar tarefas do daemon ou tarefas cron em meu nome. Yuk.

    
por 24.08.2013 / 01:14