Esta es una pregunta que iba a publicar aquí hace unas semanas. Al igual que terdon , entendí que a .bashrc
solo se obtiene para shells interactivos de Bash, por lo que no debería ser necesario .bashrc
verificar si se está ejecutando en un shell interactivo. Confusamente, todas las distribuciones que uso (Ubuntu, RHEL y Cygwin) tenían algún tipo de verificación (prueba $-
o $PS1
) para garantizar que el shell actual sea interactivo. No me gusta la programación de culto de carga, así que empecé a entender el propósito de este código en mi .bashrc
.
Bash tiene un estuche especial para proyectiles remotos
Después de investigar el problema, descubrí que los proyectiles remotos se tratan de manera diferente. Si bien los shells Bash no interactivos normalmente no ejecutan ~/.bashrc
comandos al inicio, se hace un caso especial cuando el demonio de shell remoto invoca el shell :
Bash intenta determinar cuándo se está ejecutando con su entrada estándar conectada a una conexión de red, como cuando la ejecuta el demonio de shell remoto, generalmente rshd
, o el demonio 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 es legible. No hará esto si se invoca como sh
. La --norc
opción se puede usar para inhibir este comportamiento, y la --rcfile
opción se puede usar para forzar la lectura de otro archivo, pero generalmente rshd
ni sshd
invocar el shell con esas opciones o permitir que se especifiquen.
Ejemplo
Inserte lo siguiente al comienzo de un control remoto .bashrc
. (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
in $-
indica que el shell no es interactivo .
- No se lleva
-
en $0
indica que la cáscara no es un shell de entrada .
Las funciones de shell definidas en el control remoto .bashrc
también se pueden ejecutar:
$ ssh remote_host fun
bashrc
functions work
Me di cuenta de que la ~/.bashrc
está solamente proceden cuando se especifica un comando como argumento para ssh
. Esto tiene sentido: cuando ssh
se usa para iniciar un shell de inicio de sesión normal .profile
o cuando .bash_profile
se ejecuta (y .bashrc
solo se obtiene si uno de estos archivos lo hace explícitamente).
El principal beneficio que puedo ver al haber .bashrc
obtenido al ejecutar 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 de archivos remotas pueden fallar
Esto no suele ser un problema cuando rsh
o ssh
se utiliza para iniciar un intérprete interactivo de ingreso o cuando los proyectiles no interactivas se utilizan 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
comando. No se menciona esto en la página de manual, solo una mención que se scp
utiliza ssh
para la transferencia de datos. Esto tiene la consecuencia de que si .bashrc
contiene algún comando que imprima a la salida estándar, las transferencias de archivos fallarán , por ejemplo,
scp falla sin error .
Vea también este informe de error relacionado con Red Hat de hace 15 años, scp se rompe cuando hay un comando echo en / etc / bashrc (que finalmente se cerró como WONTFIX
).
Por qué scp
y sftp
fallar
SCP (Copia segura) y SFTP (Protocolo seguro de transferencia de archivos) tienen sus propios protocolos para que los extremos locales y remotos 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. De acuerdo con un FAQ del Snail Book
Lo que sucede a menudo, sin embargo, es que hay declaraciones, ya sea en el sistema de archivos de inicio o la cáscara de cada usuario en el servidor ( .bashrc
, .profile
,
/etc/csh.cshrc
, .login
, etc.), que los mensajes de texto de salida de entrada, destinado a ser leído por los seres humanos (como fortune
, echo "Hi there!"
, etc.)
Dicho código solo debe producir resultados en inicios de sesión interactivos, cuando hay una
tty
entrada estándar adjunta. 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 cual los archivos de inicio de la shell son relevantes, es que sshd
emplea la 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.) tiene efecto cuando se ejecutan comandos remotos.
- La práctica común de configurar el shell de una cuenta en / bin / false para deshabilitarla evitará que el propietario ejecute comandos, en caso de que la autenticación aún tenga éxito accidentalmente por alguna razón.
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 cómo ejecutar scp con perfiles de shell habladores 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 scp
en que en modo fuente espera la confirmación del primer mensaje de protocolo. Si no es 0 binario, espera que sea una notificación de un problema remoto y espera a que más caracteres formen un mensaje de error hasta que llegue la nueva línea. Como no imprimiste otra línea nueva después de la primera, tu local scp
solo permanece en un bucle, bloqueado read(2)
. Mientras tanto, después de que el perfil de shell se procesó en el lado remoto, scp
se inició el modo sumidero, que también se bloquea 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 es deseable establecer variables de shell, alias y definir funciones, y la impresión de cualquier texto para estandarizar es activamente perjudicial 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
.