¿Por qué los shells interactivos en los shells de inicio de sesión de OSX son predeterminados?

43

En Linux y, que yo sepa, todos los sistemas Unix, emuladores de terminal ejecutan shells interactivos sin inicio de sesión de forma predeterminada. Esto significa que, para bash, el shell iniciado:

Cuando se inicia un shell interactivo que no es un shell de inicio de sesión, bash lee y ejecuta comandos desde /etc/bash.bashrcy ~/.bashrc, si existen estos archivos. Esto puede inhibirse mediante el uso de la --norc opción.

La --rcfile opción de archivo obligará a bash a leer y ejecutar comandos desde el archivo en lugar de /etc/bash.bashrcy ~/.bashrc.

Y para los shells de inicio de sesión:

Cuando se invoca bash como un shell de inicio de sesión interactivo o como un shell no interactivo con la --loginopción, primero lee y ejecuta comandos del archivo /etc/profile, si ese archivo existe. Después de leer ese archivo, busca ~/.bash_profile, ~/.bash_loginy ~/.profile, en ese orden, y lee y ejecuta órdenes desde el primero que existe y es legible.

La --noprofileopción se puede usar cuando se inicia el shell para inhibir este comportamiento.

Sin embargo, en OSX, el shell predeterminado (que es bash) se inició en el terminal predeterminado (Terminal.app) en realidad fuentes ~/.bash_profileo ~.profileetc. En otras palabras, actúa como un shell de inicio de sesión.

Pregunta principal : ¿Por qué el shell interactivo predeterminado es un shell de inicio de sesión en OSX? ¿Por qué OSX eligió hacer esto? Esto significa que todas las instrucciones / tutoriales para cosas basadas en shell que mencionan cambios en las cosas ~/.bashrcfallarán en OSX o viceversa ~/.profile. Aún así, si bien muchas acusaciones pueden dirigirse a Apple, contratar desarrolladores incompetentes o idiotas no es una de ellas. Presumiblemente, tenían una buena razón para esto, entonces, ¿por qué?

Preguntas: ¿Terminal.app realmente ejecuta un shell de inicio de sesión interactivo o ha cambiado el comportamiento de bash? ¿Es esto específico para Terminal.app o es independiente del emulador de terminal?

terdon
fuente
2
Terminal.app ejecuta un shell de inicio de sesión. No sé por qué Apple eligió hacer eso.
Gilles 'SO- deja de ser malvado'
Por cierto, a partir de macOS Catalina , el shell predeterminado es zsh .
Basil Bourque

Respuestas:

33

La forma en que se supone que el trabajo es que, en el momento en que obtener pronta una concha, tanto .profiley .bashrcse han ejecutado. Los detalles específicos de cómo llegar a ese punto son de relevancia secundaria, pero si alguno de los archivos no se ejecuta en absoluto, tendría un shell con configuraciones incompletas.

La razón por la que los emuladores de terminal en Linux (y otros sistemas basados ​​en X) no necesitan ejecutarse .profileellos mismos es que normalmente ya se habrán ejecutado cuando iniciaste sesión en X. Se .profilesupone que la configuración en es del tipo que puede ser heredado por subprocesos, por lo tanto, siempre y cuando se ejecute una vez cuando inicie sesión (por ejemplo, a través de .Xsession), no será necesario volver a ejecutar más subcapas.

Como explica la página wiki de Debian vinculada por Alan Shutko:

" Entonces, ¿por qué hay .bashrcun archivo separado .bash_profile? Esto se hace principalmente por razones históricas, cuando las máquinas eran extremadamente lentas en comparación con las estaciones de trabajo actuales. Procesar los comandos en .profileo .bash_profilepodría llevar bastante tiempo, especialmente en una máquina donde gran parte del trabajo tenía que hacerse mediante comandos externos (pre-bash). Por lo tanto, los comandos de configuración inicial difíciles, que crean variables de entorno que pueden pasarse a procesos secundarios, se colocan .bash_profile. Se colocan las configuraciones transitorias y los alias que no se heredan en .bashrcforma que puedan volver a ser leídas por cada subnivel ".

Las mismas reglas también se aplican a OSX, excepto por una cosa: la GUI de OSX no se ejecuta .profileal iniciar sesión, aparentemente porque tiene su propio método para cargar la configuración global. Pero eso significa que un emulador de terminal en OSX hace que tenga que ejecutar .profile(contando la concha de su lanzamiento que es un intérprete de ingreso), de lo contrario acabaría con una cáscara potencialmente lisiado.


Ahora, una especie de peculiaridad tonta de bash, no compartida por la mayoría de los otros shells, es que no se ejecutará automáticamente .bashrcsi se inicia como un shell de inicio de sesión. La solución estándar para eso es incluir algo como los siguientes comandos en .bash_profile:

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

Alternativamente, es posible no tener ninguno .bash_profile, y solo incluir algún código específico de bash en el .profilearchivo genérico para ejecutar .bashrcsi es necesario.

Si el OSX predeterminado .bash_profileo .profile no hace esto, entonces eso podría decirse que es un error. En cualquier caso, la solución adecuada es simplemente agregar esas líneas .bash_profile.


Editar: como señala Strugee , el shell predeterminado en OSX solía ser tcsh, cuyo comportamiento es mucho más sensato a este respecto: cuando se ejecuta como un shell de inicio de sesión interactivo, tcsh lee automáticamente ambos .profile y .tcshrc / .cshrc, y por lo tanto no necesita soluciones alternativas como el .bash_profiletruco mostrado anteriormente.

En base a esto, estoy 99% seguro de que la falla de OSX para proporcionar un valor predeterminado apropiado .bash_profilees porque, cuando cambiaron de tcsh a bash, la gente de Apple simplemente no notó esta pequeña verruga en el comportamiento de inicio de bash. Con tcsh, no se necesitaban tales trucos: iniciar tcsh como un shell de inicio de sesión desde un emulador de terminal OSX Just Plain Works y hace lo correcto sin tales problemas.

Ilmari Karonen
fuente
1
Gracias, como que sabía todo eso. Mi pregunta es ¿por qué OSX eligió configurar de tal manera que se volviera .bashrcirrelevante? ¿Por qué eligieron hacer que todos los shells inicien sesión? Por lo que puedo decir, solo su última oración aborda eso y solo para decir que es un error.
terdon
1
No, el problema es que comienzan con shells de inicio de sesión en sus emuladores de terminal. Los archivos de puntos son un comportamiento predeterminado de bash, al iniciar los shells de inicio de sesión se leerá el perfil, etc., no bashrc, etc. La pregunta es por qué se ejecutan los shells de inicio de sesión en lugar de los que no son de inicio de sesión.
terdon
2
Sí, y tanto Alan como yo hemos explicado que es porque, a diferencia de Linux, OSX no se ejecuta .profilecuando el usuario inicia sesión en la GUI, por lo que debe ejecutarlo más tarde para obtener variables de entorno como $PATH, que normalmente están configuradas .profile, configuradas correctamente . El hecho de que, como efecto secundario, esto hace que .bashrcno se origine es un error; puede discutir si se trata de un error en bash o en OSX, pero eso no cambia el hecho de que el comportamiento correcto sería garantizar que se carguen tanto las variables de entorno .profilecomo la configuración de configuración de bash .bashrc.
Ilmari Karonen
1
Tener .bashrcfuente .profilesería una mala idea, ya que haría que cada subshell se volviera a ejecutar .profile. Por lo menos, esto causaría .profilemodismos comunes como export PATH = "$HOME/bin:$PATH"seguir anteponiendo entradas redundantes $PATH. Tener .profilefuente .bashrctiene mucho más sentido, pero solo después de verificar que el shell bajo el que se ejecuta es, de hecho, bash. Tener la .bash_profilefuente de ambos .profile y .bashrc , como sugerí anteriormente, es, en mi opinión, la opción más sensata.
Ilmari Karonen
2
Y digo la respuesta a "¿por qué usan un shell de inicio de sesión?" es "porque necesitan de carga .profile", mientras que la respuesta a "¿Por qué no la fuente .bashrcde la .profile, entonces?" es "porque es un error!" En serio, eso no puede ser una decisión intencional; es simplemente algo que pasaron por alto, presumiblemente porque, en el ecosistema de Mac, los shells son ciudadanos de segunda clase con los que la mayoría de los usuarios no deben lidiar. (Sal. Véase también la respuesta de Strugee para una explicación histórica; es casi seguro que es una regresión del cambio de tcsh a bash.)
Ilmari Karonen
14

La razón principal por la que las aplicaciones de terminal X ejecutan shells sin inicio de sesión de forma predeterminada es que al principio de su tiempo, su .Xsession habría ejecutado el .profile para configurar sus elementos de inicio de sesión iniciales. Luego, dado que todo ya estaba configurado, las aplicaciones de terminal no necesitaban ejecutarlo, podían ejecutar el .bashrc. La discusión de por qué esto sería importante está en https://wiki.debian.org/DotFiles :

Tomemos xdm como ejemplo. Pierre regresa de vacaciones un día y descubre que su administrador del sistema ha instalado xdm en el sistema Debian. Inicia sesión muy bien, y xdm lee su archivo .xsession y ejecuta fluxbox. ¡Todo parece estar bien hasta que recibe un mensaje de error en la ubicación incorrecta! Como anula la variable LANG en su .bash_profile, y dado que xdm nunca lee .bash_profile, su variable LANG ahora está establecida en en_US en lugar de fr_CA.

Ahora, la solución ingenua a este problema es que en lugar de iniciar "xterm", podría configurar su administrador de ventanas para iniciar "xterm -ls". Este indicador le dice a xterm que, en lugar de iniciar un shell normal, debería iniciar un shell de inicio de sesión. Bajo esta configuración, xterm genera / bin / bash pero pone "- / bin / bash" (o tal vez "-bash") en el vector de argumento, por lo que bash actúa como un shell de inicio de sesión. Esto significa que cada vez que abre un nuevo xterm, leerá / etc / profile y .bash_profile (comportamiento de bash incorporado), y luego .bashrc (porque .bash_profile dice hacer eso). Puede parecer que esto funciona bien al principio: sus archivos de puntos no son pesados, por lo que ni siquiera nota el retraso, pero hay un problema más sutil. También lanza un navegador web directamente desde su menú de fluxbox, y el navegador web hereda la variable LANG de fluxbox, que ahora está configurada en la configuración regional incorrecta. Entonces, aunque sus xterms pueden estar bien, y cualquier cosa lanzada desde sus xterms puede estar bien, su navegador web todavía le está dando páginas en la ubicación incorrecta.

En OS X, los entornos de usuario no se inician con una pila de scripts de shell, y launchd no obtiene .profile en ningún momento. (Es una lástima, ya que significa que es mucho más molesto establecer variables de entorno, pero así es la vida). Dado que no es así, ¿cuándo se ejecutará .profile? ¿Solo si entraste? Eso parece un poco inútil, ya que muchas cajas nunca serán objetivos de ssh. También podría hacer que los terminales ejecuten shells de inicio de sesión de forma predeterminada, de modo que .profile se ejecute en algún momento.

¿Qué hay de .bashrc, entonces? ¿Es inútil? No. Todavía tiene el propósito que tenía en los días del VT100. Se usa para cualquier momento que abra un shell que no sea abrir una ventana de Terminal. Entonces, si sale de Emacs o vi, o si hace un usuario su.

Alan Shutko
fuente
1
La página de Debian que está citando explica por qué las .profilefuentes de Debian .bashrc, no por qué OSX decidió hacer que todos los shells inicien sesión por defecto. En realidad, estás respondiendo otra pregunta mía , ¡y gracias! Sin embargo, su respuesta no explica la elección de OSX y la cita de Debian es completamente irrelevante aquí hasta donde puedo decir (por favor avíseme si me estoy perdiendo el punto). La forma OSX hace que .bashrcetc. sea inútil y no lo hace .profilemás útil.
terdon
4

No sé por qué habrían hecho eso. Sin embargo, aquí está mi suposición.

Para empezar, vale la pena señalar que en un sistema GNU / Linux, por supuesto, puede cambiar a vt1, vt2, etc. Obtendrá un shell de inicio de sesión allí. En un sistema OS X, no hay equivalente. La única forma de acceder a las bases de UNIX es a través de un emulador de terminal o mediante el modo de usuario único (descargo de responsabilidad: en realidad nunca he usado el modo de usuario único; es IIRC impulsado por línea de comandos, pero puedo estar equivocado). Por lo tanto, en OS X, el valor predeterminado en el emulador es el predeterminado para todo el sistema.

Ahora, ¿por qué haría que el valor predeterminado sea un shell de inicio de sesión? Hay un par de razones (léase: no muchas) en las que puedo pensar para hacer esto.

  • Proporciona una experiencia de usuario consistente si ingresa SSH en la caja. (Especialmente importante para la edición del servidor de OS X: presumiblemente si está ejecutando un servidor OS X, es un novato).
  • El shell predeterminado de OS X solía ser tcsh. Esto es una suposición tan descabellada como puede ser, pero puede ser que tcshnormalmente hiciera algo cuando se ejecutaba como un shell de inicio de sesión y el patrón histórico se atascara. (Sin embargo, lo dudo, tal vez uno de los clientes habituales más antiguos podría decirnos).
  • "Somos Apple. Somos los proveedores de la distribución de UNIX más grande del planeta. No importa cuán triviales sean nuestras razones; si tomamos una decisión, su herramienta debe lidiar con eso".

Honestamente, he estado usando Darwin durante ~ 6 años y no puedo responder esta pregunta correctamente. Realmente tampoco tiene sentido para mí.

Para responder a su pregunta, bashno está parcheado ni nada (al menos para esto). El emulador de terminal predeterminado ejecuta shells de inicio de sesión de forma predeterminada, y presumiblemente iTerm lo copia.

Strugee
fuente
1
+1 por mencionar tcsh, ya que su comportamiento es mucho más sensato a este respecto que el de bash: cuando se inicia como un shell de inicio de sesión interactivo, tcsh obtiene ambas .profile y .tcshrc/ o .cshrcno requiere ningún tipo de kluges como el que di en mi respuesta. Dado eso, sospecho que este comportamiento es una regresión no fija causada por el cambio de tcsh a bash.
Ilmari Karonen
@IlmariKaronen ¿Quieres decir (aquí y allá ) que tcsh fuentes .loginy .tcshrc/ .cshrc? No tendría sentido que tcsh se originara .profile; Por lo general, contiene comandos con shsintaxis que tcshno acepta. No tengo macOS pero hice /bin/tcshmi shell de inicio de sesión en Ubuntu 16.04. .profileNo es de origen. tcsh (1) no menciona ese archivo, ni este tcsh (1) .
Eliah Kagan
3

Esta es una actualización del estado actual: las respuestas se han vuelto obsoletas a medida que se lanzan nuevas versiones de MacOSX y el comportamiento de inicio de sesión ha cambiado.

Esta pregunta fue formulada y respondida en 2014. He estado investigando el tema en un intento de crear un conjunto común .bashrc & .bash_profile para usar en diferentes distribuciones de Linux y BSD (como se llame si no son distribuciones).

Recientemente compré una Mac Mini usada con Sierra instalada, por lo que ahora tengo sistemas con 10.6, 10.10, 10.11 y 10.12. Aunque he manipulado a los más antiguos (dejando pistas sobre su estado anterior), la instalación de Sierra 10.12 no ha sido tocada.

Resultados: en 10.12 Sierra, NO hay .bashrc, .bash_profile o .profile predeterminados creados. En / etc, hay bashrc, bashrc_Apple_Terminal y profile. Contenido de / 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

Contenido 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"

El script / etc / bashrc_Apple_Terminal establece la variable PROMPT_COMMAND y configura un mecanismo para preservar el estado de la sesión para cada terminal; si se cierra la aplicación de terminal, el estado de la sesión anterior se restaura cuando la aplicación se inicia nuevamente. De lo contrario, casi nada (mínimo $ PS1) se establece en / etc / bashrc, dejando cualquier otra personalización ($ PS1 real, alias, funciones) para configurar en ~ / .bashrc y $ PATH en .bash_profile (o en .profile , originado por .bash_profile).

He confirmado que iTerm2 se comporta de la misma manera que la aplicación Terminal, excepto que el comportamiento predeterminado de iniciar una sesión de inicio de sesión es visible y se puede editar.

Si ejecuta una sesión de terminal XTerm X11 (ahora XQuartz), verá una sesión sin inicio de sesión, igual que en un sistema Linux; .bash_profile (o .profile) se omite y solo obtiene .bashrc.

Y aquí está mi respuesta:

Aunque la aplicación Terminal afirma ser un xterm (TERM = xterm-256color), no establece la variable $ DISPLAY a menos que se instale X11. Estamos viendo una simulación de un entorno X, pero no completamente real. Si ingresa SSH a otro sistema con el interruptor -X (habilite el reenvío X11), fallará porque no hay una variable $ DISPLAY. Si ha instalado X11, luego SSH en otro sistema, el reenvío X11 tendrá éxito.

En pocas palabras (y respuesta breve): la aplicación Terminal no es una verdadera terminal X11 (no establece $ DISPLAY); se comporta mucho más como un inicio de sesión SSH que una sesión XTerm, ya que tiene que ser una sesión de inicio de sesión para establecer valores desde / etc / profile y ~ / .bash_profile o ~ / .profile

donas
fuente
0

Las respuestas anteriores explicaron la razón por la cual los shells interactivos son shells de inicio de sesión en macOS de forma predeterminada: la configuración en /etc/profile, ~/.profilees heredada por un shell sin inicio de sesión en sistemas basados ​​en X, pero no en macOS . Aquí quiero recordarle que siempre debe usar el shell de inicio de sesión en macOS debido a la existencia 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

La path_helperutilidad lee el contenido de los archivos de los directorios /etc/paths.dy /etc/manpaths.d y añade su contenido a las PATHy MANPATHvariables de entorno, respectivamente. (La MANPATHvariable de entorno no se modificará a menos que ya esté configurada en el entorno).

Si está utilizando un shell sin inicio de sesión, algunas rutas no se importarán.

Creo que siempre es una buena idea que el desarrollador coloque un archivo /etc/paths.dpara importar sus valores de ruta, pero no para vincular los archivos binarios invocables en ubicaciones como /usr/bino /bin. (El valor predeterminado PATHes /usr/bin:/bin:/usr/sbin:/sbin. No todos usan Homebrew o MacPorts agregando valores personalizados PATH. Por lo tanto, no siempre hay un lugar seguro para colocar los enlaces simbólicos de los comandos invocables).

Aquí hay un ejemplo de archivos en /etc/paths.d. Básicamente estás poniendo un valor en cada línea.

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

Referencia:

Simba
fuente