¿Diferencia entre Shell de inicio de sesión y Shell sin inicio de sesión?

318

Entiendo la diferencia básica entre un shell interactivo y un shell no interactivo. Pero, ¿qué diferencia exactamente un shell de inicio de sesión de un shell sin inicio de sesión?

¿Puede dar ejemplos de usos de un shell interactivo sin inicio de sesión ?

Igorio
fuente
45
Creo que la pregunta está mejor redactada como " ¿Por qué deberíamos / deberíamos importarnos diferenciar los shells de inicio y no inicio de sesión?" Muchos lugares en la web ya nos dicen cuáles son las diferencias, en términos de qué archivos de inicio lee cada uno; pero ninguno de ellos parece responder al "por qué" de manera satisfactoria y convincente. Ejemplos de casos de uso en los que definitivamente no quieres uno u otro comportamiento sería genial.
Kal
2
@Kal Esto tendría que ser una pregunta diferente, ya que ninguna respuesta aquí en realidad cubre eso. Editar: En realidad, aquí está: ¿POR QUÉ un shell de inicio de sesión sobre un shell sin inicio de sesión ? .
Skippy le Grand Gourou

Respuestas:

304

Un shell de inicio de sesión es el primer proceso que se ejecuta con su ID de usuario cuando inicia sesión para una sesión interactiva. El proceso de inicio de sesión le dice al shell que se comporte como un shell de inicio de sesión con una convención: pasar el argumento 0, que normalmente es el nombre del ejecutable del shell, con un -carácter antepuesto (por ejemplo, -bashmientras que normalmente sería bash. Los shells de inicio de sesión normalmente leen un archivo que cosas como establecer variables de entorno: /etc/profiley ~/.profilepara el shell Bourne tradicional, ~/.bash_profileadicionalmente para bash , /etc/zprofiley ~/.zprofilepara zsh , /etc/csh.loginy ~/.loginpara csh, etc.

Cuando inicia sesión en una consola de texto, o a través de SSH, o con su -, obtiene un shell de inicio de sesión interactivo . Cuando inicia sesión en modo gráfico (en un administrador de pantalla X ), no obtiene un shell de inicio de sesión, sino que obtiene un administrador de sesión o un administrador de ventanas.

Es raro ejecutar un shell de inicio de sesión no interactivo , pero algunas configuraciones de X lo hacen cuando inicia sesión con un administrador de pantalla, para organizar la lectura de los archivos de perfil. Otras configuraciones (esto depende de la distribución y del administrador de pantalla) leen /etc/profiley ~/.profileexplícitamente, o no las leen. Otra forma de obtener un shell de inicio de sesión no interactivo es iniciar sesión de forma remota con un comando que se pasa a través de una entrada estándar que no es un terminal, por ejemplo ssh example.com <my-script-which-is-stored-locally(a diferencia de ssh example.com my-script-which-is-on-the-remote-machine, que ejecuta un shell no interactivo, sin inicio de sesión).

Cuando inicia un shell en un terminal en una sesión existente (pantalla, terminal X, búfer de terminal Emacs, un shell dentro de otro, etc.), obtiene un shell interactivo sin inicio de sesión . Ese shell puede leer un archivo de configuración de shell ( ~/.bashrcpara bash invocado como bash, /etc/zshrcy ~/.zshrcpara zsh, /etc/csh.cshrcy ~/.cshrcpara csh, el archivo indicado por la ENVvariable para shells compatibles con POSIX / XSI como dash, ksh y bash cuando se invoca como sh, $ENVsi está configurado y ~/.mkshrcpara mksh, etc.).

Cuando un shell ejecuta un script o un comando pasado en su línea de comando, es un shell no interactivo, sin inicio de sesión . Tales shells se ejecutan todo el tiempo: es muy común que cuando un programa llama a otro programa, realmente ejecuta un pequeño script en un shell para invocar a ese otro programa. Algunos shells leen un archivo de inicio en este caso (bash ejecuta el archivo indicado por la BASH_ENVvariable, zsh se ejecuta /etc/zshenvy ~/.zshenv), pero esto es arriesgado: el shell se puede invocar en todo tipo de contextos, y casi no hay nada que pueda hacer que no romper algo.

Estoy simplificando un poco, mira el manual para los detalles sangrientos.

Gilles
fuente
2
¿Podría dar un ejemplo de cómo ejecutar bashun shell de inicio de sesión no interactivo?
Piotr Dobrogost
13
@PiotrDobrogostecho $- | bash -lx
Gilles
1
No sé si esto es cierto en general, pero quiero señalar que cuando abro un nuevo terminal (en osx usando la configuración predeterminada), obtengo un shell de inicio de sesión aunque nunca escriba mi nombre de usuario o contraseña.
Kevin Wheeler
44
@KevinWheeler En OSX, de forma predeterminada, la aplicación Terminal ejecuta un shell de inicio de sesión. (Como explico, el programa que inicia el shell decide si el shell actúa como un shell de inicio de sesión). Esa no es la forma normal de hacer las cosas.
Gilles
2
@IAmJulianAcosta Si FOOes una variable de entorno (es decir, .profilecontiene export FOO=something), está disponible para todos los subprocesos, incluidos foo.sh. Si cambia .profilea export FOO=something_else, ./foo.shse imprimirá somethinghasta la próxima vez que inicie sesión.
Gilles
48

Para saber si está en un shell de inicio de sesión:

prompt> echo $0
-bash # "-" is the first character. Therefore, this is a login shell.

prompt> echo $0
bash # "-" is NOT the first character. This is NOT a login shell.

En Bash, también puedes usar shopt login_shell:

prompt> shopt login_shell
login_shell     off

(o onen un shell de inicio de sesión).

Se puede encontrar información en man bash(buscar Invocación). Aquí hay un extracto:

Un shell de inicio de sesión es aquel cuyo primer carácter del argumento cero es un -, o uno que comenzó con la opción --login.

Puedes probar esto tú mismo. Cada vez que utiliza SSH, está utilizando un shell de inicio de sesión. Por ejemplo:

prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash

La importancia de usar un shell de inicio de sesión es que cualquier configuración /home/user/.bash_profilese ejecutará. Aquí hay un poco más de información si está interesado (de man bash)

"Cuando se invoca bash como un shell de inicio de sesión interactivo, o como un shell no interactivo con la opción --login, 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 opción --noprofile se puede utilizar cuando la cáscara se inicia para inhibir este comportamiento."

Timothy Pulliam
fuente
23

En una cáscara de inicio de sesión, argv[0][0] == '-'. Así es como sabe que es un shell de inicio de sesión.

Y luego, en algunas situaciones, se comporta de manera diferente dependiendo de su estado de "shell de inicio de sesión". Por ejemplo, un shell, que no es un shell de inicio de sesión, no ejecutaría un comando "cerrar sesión".

BOPOHOK
fuente
44
Según man bash, con énfasis agregado, "un shell de inicio de sesión es aquel cuyo primer carácter del argumento cero es un -, o uno comenzó con la opción --login " .
Comodín el
18

Un shell iniciado en una nueva terminal en una GUI sería un shell interactivo sin inicio de sesión. Obtendría su .bashrc, pero no su .profile, por ejemplo.

Julian
fuente
4

Explicaré la gran respuesta de Gilles, combinada con el método de Timothy para verificar el tipo de shell de inicio de sesión.

Si te gusta ver las cosas por ti mismo, prueba los siguientes fragmentos y escenarios.

Comprobando si el shell es (no) interactivo

if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi

Comprobando si shell es (no) inicio de sesión

Si la salida de echo $0comienza con -, es shell de inicio de sesión ( echo $0ejemplo de salida:) -bash. De lo contrario, es un shell sin inicio de sesión ( echo $0ejemplo de salida:) bash.

if echo $0 | grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;

Combinemos los dos anteriores para obtener ambas piezas de información a la vez:

THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; 
THIS_SHELL_LOGIN_TYPE='non-login'; 
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; 
if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

Escenarios:

Sesión SSH típica sin opciones especiales.

ssh ubuntu@34.247.105.87
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

ubuntu@ip-172-31-0-70:~$ THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_LOGIN_TYPE='non-login';
ubuntu@ip-172-31-0-70:~$ if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
ubuntu@ip-172-31-0-70:~$ if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
ubuntu@ip-172-31-0-70:~$ echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

interactive/login

Ejecutar script o ejecutar explícitamente a través de un nuevo shell

ubuntu@ip-172-31-0-70:~$  bash -c 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; 
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Ejecutar script local de forma remota

ssh ubuntu@34.247.105.87 < checkmy.sh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

non-interactive/login

Ejecutar un comando sobre ssh de forma remota

ssh ubuntu@34.247.105.87 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

non-interactive/non-login

Ejecutar un comando sobre ssh de forma remota con el -tinterruptor

Puede solicitar explícitamente el shell interactivo cuando desee ejecutar el comando de forma remota a través de ssh utilizando el -tinterruptor.

ssh ubuntu@34.247.105.87 -t 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

Nota: sobre el tema de por qué ejecutar comandos de forma remota no hay login shellmás información aquí .

Patrik Stas
fuente