Por que os shells interativos nos shells de login do OSX são padrão?

34

No Linux e, no meu conhecimento, em todos os sistemas Unix, os emuladores de terminal executam shells interativos e não-login por padrão. Isso significa que, para o bash, o shell iniciado irá:

When an interactive shell that is not a login shell is started, bash reads and executes commands from /etc/bash.bashrc and ~/.bashrc, if these files exist. This may be inhibited by using the --norc option.

The --rcfile file option will force bash to read and execute commands from file instead of /etc/bash.bashrc and ~/.bashrc.

E para shells de login:

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

The --noprofile option may be used when the shell is started to inhibit this behavior.

No OSX, no entanto, o shell padrão (que é bash) iniciado no terminal padrão (Terminal.app), na verdade, origina ~/.bash_profile ou ~.profile etc. Em outras palavras, ele age como um shell de login.

Pergunta principal : Por que o shell interativo padrão é um shell de login no OSX? Por que a OSX escolheu fazer isso? Isso significa que todas as instruções / tutoriais para coisas baseadas em shell que mencionam alterações em ~/.bashrc falharão no OSX ou vice-versa para ~/.profile . Ainda assim, enquanto muitas acusações podem ser feitas na Apple, contratar desenvolvedores incompetentes ou idiotas não é uma delas. Presumivelmente, eles tinham uma boa razão para isso, então por que?

Subquestions: O Terminal.app realmente executa um shell de login interativo ou eles mudaram o comportamento do bash? Isso é específico para o Terminal.app ou é independente do emulador de terminal?

    
por terdon 14.03.2014 / 01:14

5 respostas

29

A maneira como supõe funcionar é que, no ponto em que você recebe um prompt de shell, ambos .profile e .bashrc foram executados. Os detalhes específicos de como chegar a esse ponto são de relevância secundária, mas se nenhum dos arquivos for executado, você terá um shell com configurações incompletas.

A razão pela qual os emuladores de terminal no Linux (e outros sistemas baseados em X) não precisam para executar .profile é que ele normalmente já teria sido executado quando você efetuou login no X. As configurações em .profile devem ser do tipo que pode ser herdada por subprocessos, portanto, desde que seja executada uma vez quando você efetuar login (por exemplo, via .Xsession ), nenhuma outra subshell precisará ser executada novamente. isso.

Como a página wiki Debian ligada por Alan Shutko explica:

"Why is .bashrc a separate file from .bash_profile, then? This is done for mostly historical reasons, when machines were extremely slow compared to today's workstations. Processing the commands in .profile or .bash_profile could take quite a long time, especially on a machine where a lot of the work had to be done by external commands (pre-bash). So the difficult initial set-up commands, which create environment variables that can be passed down to child processes, are put in .bash_profile. The transient settings and aliases which are not inherited are put in .bashrc so that they can be re-read by every subshell."

Todas as mesmas regras também se aplicam ao OSX, exceto por uma coisa - a GUI do OSX não executa .profile quando você efetua login, aparentemente porque tem seu próprio método de carregar configurações globais. Mas isso significa que um emulador de terminal no OSX precisa executar o .profile (informando ao shell que ele inicia um shell de login), caso contrário você acabaria com um shell potencialmente danificado. / p>

Agora, uma espécie de peculiaridade boba do bash, não compartilhada pela maioria dos outros shells, é que ela não executará .bashrc automaticamente se for iniciada como um shell de login. A solução padrão para isso é incluir algo como os seguintes comandos em .bash_profile :

[[ -e ~/.profile ]] && source ~/.profile    # load generic profile settings
[[ -e ~/.bashrc  ]] && source ~/.bashrc     # load aliases etc.

Como alternativa, é possível não ter .bash_profile , e apenas incluir algum código específico bash no arquivo genérico .profile para executar .bashrc , se necessário.

Se o padrão do OSX .bash_profile ou .profile não fizer isso, então isso é um bug. Em qualquer caso, a solução adequada é simplesmente adicionar essas linhas a .bash_profile .

Editar: Como notas de resistência , o shell padrão no OSX costumava ser tcsh, cujo comportamento é muito melhor a esse respeito: quando executado como um shell de login interativo, o tcsh lê automaticamente .profile e .tcshrc / .cshrc e, portanto, não precisa de soluções alternativas como% truque de.bash_profile mostrado acima.

Com base nisso, tenho 99% de certeza de que a falha do OSX em fornecer um padrão apropriado .bash_profile é porque, quando eles mudaram de tcsh para bash, o pessoal da Apple simplesmente não percebeu essa pequena verruga comportamento de inicialização do bash. Com o tcsh, esses truques não eram necessários - iniciar o tcsh como um shell de login de um emulador de terminal do OSX, o Just Plain Works, e fazer a coisa certa sem esses kluges.

    
por 14.03.2014 / 09:54
13

A principal razão pela qual os aplicativos do terminal X executam shells não-login por padrão é que, no início do tempo, sua .Xsession teria executado o .profile para configurar seus itens de login iniciais. Então, como tudo já estava configurado, os aplicativos de terminal não precisavam executá-lo, eles podiam executar o .bashrc. A discussão de por que isso importaria está no link :

Let's take xdm as an example. pierre comes back from vacation one day and discovers that his system administrator has installed xdm on the Debian system. He logs in just fine, and xdm reads his .xsession file and runs fluxbox. Everything seems to be OK until he gets an error message in the wrong locale! Since he overrides the LANG variable in his .bash_profile, and since xdm never reads .bash_profile, his LANG variable is now set to en_US instead of fr_CA.

Now, the naive solution to this problem is that instead of launching "xterm", he could configure his window manager to launch "xterm -ls". This flag tells xterm that instead of launching a normal shell, it should launch a login shell. Under this setup, xterm spawns /bin/bash but it puts "-/bin/bash" (or maybe "-bash") in the argument vector, so bash acts like a login shell. This means that every time he opens up a new xterm, it will read /etc/profile and .bash_profile (built-in bash behavior), and then .bashrc (because .bash_profile says to do that). This may seem to work fine at first -- his dot files aren't heavy, so he doesn't even notice the delay -- but there's a more subtle problem. He also launches a web browser directly from his fluxbox menu, and the web browser inherits the LANG variable from fluxbox, which is now set to the wrong locale. So while his xterms may be fine, and anything launched from his xterms may be fine, his web browser is still giving him pages in the wrong locale.

No OS X, os ambientes do usuário não são iniciados por uma pilha de scripts de shell, e o launchd não fornece o .profile a qualquer momento. (Isso é uma pena, pois significa que é muito mais irritante definir variáveis de ambiente, mas tal é a vida.) Como não funciona, quando é que ele executa o .profile? Somente se você estiver interessado? Isso parece meio sem sentido, já que muitas caixas nunca serão alvos de ssh. Pode também fazer com que os terminais executem shells de login por padrão, para que o .profile seja executado em algum momento.

E sobre .bashrc, então? Isso é inútil? Não. Ainda tem o propósito que tinha nos dias do VT100. Ele é usado a qualquer momento em que você abrir um shell diferente de abrir uma janela do Terminal. Então, se você desembolsar do Emacs ou vi, ou se você fizer um su user.

    
por 14.03.2014 / 02:00
4

Eu não sei porque eles teriam feito isso. No entanto, aqui está o meu palpite.

Para começar, vale a pena notar que em um sistema GNU / Linux, você pode mudar para vt1, vt2, etc. Você obtém um shell de login lá. Em um sistema OS X, não há equivalente. A única maneira de acessar os fundamentos do UNIX é através de um emulador de terminal ou através do modo de usuário único (disclaimer: Eu nunca usei o modo de usuário único; é o IIRC comandado por linha de comando, mas posso estar errado). Portanto, no OS X, qualquer que seja o padrão no emulador, é o padrão para todo o sistema.

Agora, por que você tornaria o padrão um shell de login? Há um par (leia-se: não muitas) razões pelas quais posso pensar em fazer isso.

  • Ele fornece uma experiência de usuário consistente se você tiver SSH na caixa. (Especialmente importante para a edição do servidor do OS X - presumivelmente, se você estiver executando um servidor OS X, você é um novato.)
  • O shell padrão do OS X costumava ser tcsh . Esse é o máximo que você pode adivinhar, mas pode ser que tcsh normalmente tenha feito alguma coisa quando executado como um shell de login e o padrão histórico ficou preso. (Duvido, no entanto - talvez um dos frequentadores mais antigos pudesse nos dizer).
  • "Somos a Apple. Somos os fornecedores da maior distribuição de UNIX do planeta. Não importa quão triviais sejam nossos motivos; se tomarmos uma decisão, sua ferramenta deverá lidar com isso."

Honestamente, tenho usado o Darwin há ~ 6 anos e não posso responder a essa pergunta corretamente. Também não faz sentido para mim.

Para responder sua subquestão, bash não é corrigido nem nada (pelo menos para isso). O emulador de terminal padrão executa shells de login por padrão e, presumivelmente, o iTerm copia isso.

    
por 14.03.2014 / 01:42
3

Esta é uma atualização do status atual: as respostas ficaram obsoletas quando novas versões do MacOSX foram lançadas e o comportamento de login mudou.

Esta pergunta foi feita e respondida em 2014. Eu tenho pesquisado o assunto na tentativa de construir um .bashrc & comum; .bash_profile configurado para usar em diferentes distribuições Linux e BSD (seja lá o que eles chamam, se não forem distros).

Comprei recentemente um Mac Mini usado com o Sierra instalado, por isso agora tenho sistemas com 10.6, 10.10, 10.11 e 10.12. Embora eu tenha analisado os mais antigos (deixando pistas para o status anterior), a instalação do Sierra 10.12 está intocada.

Resultados: No 10.12 Sierra, NÃO há nenhum padrão .bashrc, .bash_profile ou .profile criado. Em / etc, existem bashrc, bashrc_Apple_Terminal e profile. Conteúdo do / etc / profile:

# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval '/usr/libexec/path_helper -s'
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

Conteúdo de / etc / bashrc:

# System-wide .bashrc file for interactive bash(1) shells.
if [ -z "$PS1" ]; then
   return
fi

PS1='\h:\W \u\$ '
# Make bash check its window size after a process completes
shopt -s checkwinsize

[ -r "/etc/bashrc_$TERM_PROGRAM" ] && . "/etc/bashrc_$TERM_PROGRAM"

O script / etc / bashrc_Apple_Terminal define a variável PROMPT_COMMAND e configura um mecanismo para preservar o estado da sessão para cada terminal; se o aplicativo terminal for encerrado, o status da sessão anterior será restaurado quando o aplicativo for iniciado novamente. Caso contrário, quase nada (mínimo de $ PS1) é definido em / etc / bashrc, deixando qualquer outra customização (real $ PS1, aliases, funções) definida em ~ / .bashrc e $ PATH em .bash_profile (ou em .profile , originado em .bash_profile).

Confirmei que o iTerm2 se comporta da mesma forma que o aplicativo Terminal, exceto que o comportamento padrão de iniciar uma sessão de login é visível e pode ser editado.

Se você executar uma sessão de terminal XTerm X11 (agora XQuartz), verá uma sessão de não-login, a mesma que em um sistema Linux; .bash_profile (ou .profile) é ignorado e você simplesmente obtém .bashrc.

E aqui está minha resposta:

Embora o aplicativo Terminal afirme ser um xterm (TERM = xterm-256color), ele não define a variável $ DISPLAY, a menos que o X11 esteja instalado. Estamos vendo uma simulação de um ambiente X, mas não completamente real. Se você executar o SSH em outro sistema com o comutador -X (ativar o encaminhamento do X11), ele falhará porque não há nenhuma variável $ DISPLAY. Se você instalou o X11, depois o SSH em outro sistema, o encaminhamento do X11 será bem-sucedido.

Linha de fundo (e resposta curta): O aplicativo Terminal não é um verdadeiro terminal X11 (não define $ DISPLAY); ele se comporta muito mais como um login SSH do que uma sessão XTerm, pois tem que ser uma sessão de login para definir valores de / etc / profile e ~ / .bash_profile ou ~ / .profile

    
por 09.07.2017 / 18:42
0

As respostas acima explicaram o motivo pelo qual shells interativas são shells de login no macOS por padrão: configurações em /etc/profile , ~/.profile são herdadas por um shell não-login em sistemas baseados em X, mas não em macOS . Aqui eu quero lembrar que você deve sempre usar o shell de login no macOS por causa da existência de path_helper :

❯ cat /etc/profile # or cat /etc/zprofile
# System-wide .profile for sh(1)

if [ -x /usr/libexec/path_helper ]; then
    eval '/usr/libexec/path_helper -s'
fi

if [ "${BASH-no}" != "no" ]; then
    [ -r /etc/bashrc ] && . /etc/bashrc
fi

The path_helper utility reads the contents of the files in the directories /etc/paths.d and /etc/manpaths.d and appends their contents to the PATH and MANPATH environment variables respectively. (The MANPATH envi- ronment variable will not be modified unless it is already set in the environment.)

Se você estiver usando um shell que não seja de login, alguns caminhos não serão importados.

Acho sempre uma boa ideia para o desenvolvedor colocar um arquivo em /etc/paths.d para importar os valores do caminho, mas não para vincular os binários que podem ser chamados a locais como /usr/bin ou /bin . (O padrão PATH é /usr/bin:/bin:/usr/sbin:/sbin . Nem todo mundo usa Homebrew ou MacPorts adicionando valores personalizados em PATH . Portanto, nem sempre há um local seguro para colocar os links simbólicos de comandos que podem ser chamados.)

Aqui está um exemplo de arquivos em /etc/paths.d . Basicamente, você está colocando um valor em cada linha.

❯ cat /etc/paths.d/Wireshark
/Applications/Wireshark.app/Contents/MacOS

Referência:

por 25.11.2018 / 13:21

Tags