GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué Bashrc comprueba si el shell actual es interactivo?

En mi instalación de Arch, /etc/bash.bashrc y /etc/skel/.bashrc contener estas líneas:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

En Debian, /etc/bash.bashrc tiene:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

Y /etc/skel/.bashrc :

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Según man bash , sin embargo, los shells no interactivos ni siquiera leen estos archivos:

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com‐
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file‐
   name.

Si entiendo correctamente, el *.bashrc los archivos solo se leerán si BASH_ENV está configurado para señalarlos. Esto es algo que no puede suceder por casualidad y solo ocurrirá si alguien ha establecido explícitamente la variable en consecuencia.

Eso parece romper la posibilidad de que los scripts generen el .bashrc de un usuario. automáticamente configurando BASH_ENV , algo que podría venir muy bien. Dado que bash nunca leerá estos archivos cuando se ejecute de forma no interactiva a menos que se le indique explícitamente que lo haga, ¿por qué hacer el *bashrc predeterminado? ¿Los archivos no lo permiten?

Respuesta aceptada:

Esta es una pregunta que iba a publicar aquí hace unas semanas. Me gusta terdón , entendí que un .bashrc solo se obtiene para shells Bash interactivos, por lo que no debería haber necesidad de .bashrc para comprobar si se está ejecutando en un shell interactivo. Confusamente, todos las distribuciones que uso (Ubuntu, RHEL y Cygwin) tenían algún tipo de verificación (probando $- o $PS1 ) para garantizar que el shell actual sea interactivo. No me gusta la programación de culto de carga, así que me puse a entender el propósito de este código en mi .bashrc .

Bash tiene un caso especial para shells remotos

Después de investigar el problema, descubrí que shells remotos son tratados de manera diferente. Si bien los shells Bash no interactivos normalmente no ejecutan ~/.bashrc comandos al inicio, se crea un caso especial cuando el shell es invocado por un daemon de shell remoto:

Bash intenta determinar cuándo se está ejecutando con su entrada estándar
conectada a una conexión de red, como cuando lo ejecuta el shell remoto
daemon, generalmente rshd , o el daemon de shell seguro sshd . Si Bash
determina que se está ejecutando de esta manera, lee y ejecuta comandos
desde ~/.bashrc, si ese archivo existe y se puede leer. No hará esto si
se invoca como sh . El --norc puede usarse para inhibir este comportamiento,
y el --rcfile La opción puede usarse para forzar la lectura de otro archivo, pero
ni rshd ni sshd generalmente invoque el shell con esas opciones o
permita que se especifiquen.

Ejemplo

Inserte lo siguiente al comienzo de un .bashrc remoto . (Si .bashrc proviene de .profile o .bash_profile , desactívelo temporalmente durante la prueba):

echo bashrc
fun()
{
    echo functions work
}

Ejecute los siguientes comandos localmente:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • No i en $- indica que el shell es no interactivo .
  • Sin - iniciales en $0 indica que el shell no es un shell de inicio de sesión .

Funciones de shell definidas en el .bashrc remoto también se puede ejecutar:

$ ssh remote_host fun
bashrc
functions work

Noté que ~/.bashrc es solo se obtiene cuando se especifica un comando como argumento para ssh . Esto tiene sentido:cuando ssh se utiliza para iniciar un shell de inicio de sesión normal, .profile o .bash_profile se ejecutan (y .bashrc solo se obtiene si uno de estos archivos lo hace explícitamente).

Relacionado:Php:current — Devuelve el elemento actual en una matriz

El principal beneficio que puedo ver al tener .bashrc originado cuando se ejecuta un comando remoto (no interactivo) es que se pueden ejecutar funciones de shell. Sin embargo, la mayoría de los comandos en un típico .bashrc solo son relevantes en un shell interactivo, por ejemplo, los alias no se expanden a menos que el shell sea interactivo.

Las transferencias remotas de archivos pueden fallar

Esto no suele ser un problema cuando rsh o ssh se utilizan para iniciar un shell de inicio de sesión interactivo o cuando se utilizan shells no interactivos para ejecutar comandos. Sin embargo, puede ser un problema para programas como rcp , scp y sftp que usan shells remotos para transferir datos.

Resulta que el shell predeterminado del usuario remoto (como Bash) se inicia implícitamente cuando se usa el scp dominio. No se menciona esto en la página de manual, solo se menciona que scp usa ssh para su transferencia de datos. Esto tiene como consecuencia que si el .bashrc contiene cualquier comando que imprima en salida estándar, las transferencias de archivos fallarán , por ejemplo, scp falla sin error.

Por qué scp y sftp falla

SCP (Copia segura) y SFTP (Protocolo seguro de transferencia de archivos) tienen sus propios protocolos para que los extremos local y remoto intercambien información sobre los archivos que se transfieren. Cualquier texto inesperado del extremo remoto se interpreta (erróneamente) como parte del protocolo y la transferencia falla. Según una pregunta frecuente del Snail Book

Sin embargo, lo que sucede a menudo es que hay declaraciones en el sistema
o en los archivos de inicio de shell de cada usuario en el servidor (.bashrc , .profile , /etc/csh.cshrc , .login , etc.) que generan mensajes de texto al iniciar sesión,
destinados a ser leídos por humanos (como fortune , echo "Hi there!" , etc.).

Dicho código solo debe producir resultados en inicios de sesión interactivos, cuando hay un tty conectado a la entrada estándar. Si no realiza esta prueba,
insertará estos mensajes de texto donde no pertenecen:en este caso, contaminando
el flujo de protocolo entre scp2 /sftp y sftp-server .

La razón por la que los archivos de inicio de shell son relevantes es que sshd emplea el shell del usuario al iniciar cualquier programa en nombre del usuario (usando, por ejemplo, /bin/sh -c “comando”). Esta es una tradición de Unix y tiene
ventajas:

  • La configuración habitual del usuario (alias de comando, variables de entorno, umask,
    etc.) está en vigor cuando se ejecutan los comandos remotos.
  • La práctica común de establecer el shell de una cuenta en /bin/false para deshabilitar
    evitará que el propietario ejecute cualquier comando, en caso de que la autenticación
    aún tenga éxito accidentalmente por algún motivo.

Detalles del protocolo SCP

Para aquellos interesados ​​en los detalles de cómo funciona SCP, encontré información interesante en Cómo funciona el protocolo SCP, que incluye detalles sobre ¿Ejecutar scp con perfiles de shell hablador en el lado remoto? :

Por ejemplo, esto puede suceder si agrega esto a su perfil de shell en el
sistema remoto:

eco “”

¿Por qué simplemente se cuelga? Eso viene de la forma en que scp en fuente mode
espera la confirmación del primer mensaje de protocolo. Si no es binario
0, espera que sea una notificación de un problema remoto y espera
más caracteres para formar un mensaje de error hasta que llega la nueva línea. Dado que
no imprimió otra línea nueva después de la primera, su scp local simplemente
permanece en un bucle, bloqueado en read(2) . Mientras tanto, después de que el perfil de shell
se procesara en el lado remoto, scp en modo sumidero,
que también bloquea en read(2) , esperando un cero binario que indique el inicio
de la transferencia de datos.

Conclusión/TLDR

La mayoría de las declaraciones en un típico .bashrc solo son útiles para un shell interactivo, no cuando se ejecutan comandos remotos con rsh o ssh . En la mayoría de estas situaciones, no se desea establecer variables de shell, alias y definir funciones, e imprimir cualquier texto estandarizar es activamente dañino si se transfieren archivos usando programas como scp o sftp . Salir después de verificar que el shell actual no es interactivo es el comportamiento más seguro para .bashrc .


Linux
  1. ¿El propósito de .bashrc y cómo funciona?

  2. ¿Cómo verificar si un shell es de inicio de sesión/interactivo/por lotes?

  3. ¿Por qué el usuario raíz necesita permiso de Sudo?

  4. Si los procesos heredan el entorno de los padres, ¿por qué necesitamos exportar?

  5. ¿Por qué los shells interactivos están predeterminados en los shells de inicio de sesión de Osx?

Restringir Alt+Tab al monitor actual en GNOME Shell

Cómo instalar Fish, The Friendly Interactive Shell, en Linux

¿Por qué $shlvl comienza en el nivel 2 en los shells sin inicio de sesión pero en el nivel 1 en los shells de inicio de sesión en Rhel 7?

¿Regenerar .bashrc desde Shell actual?

¿Qué significa la sintaxis |&en lenguaje shell?

¿Por qué el bit setuid funciona de manera inconsistente?