Esta es una pregunta que iba a publicar aquí hace unas semanas. Al igual que terdon , entendí que a .bashrcsolo se obtiene para shells interactivos de Bash, por lo que no debería ser necesario .bashrcverificar 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 ~/.bashrccomandos 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 --norcopción se puede usar para inhibir este comportamiento, y la --rcfileopción se puede usar para forzar la lectura de otro archivo, pero generalmente rshdni sshdinvocar el shell con esas opciones o permitir que se especifiquen.
Ejemplo
Inserte lo siguiente al comienzo de un control remoto .bashrc. (Si .bashrcproviene de .profileo .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
iin $-indica que el shell no es interactivo .
- No se lleva
-en $0indica que la cáscara no es un shell de entrada .
Las funciones de shell definidas en el control remoto .bashrctambién se pueden ejecutar:
$ ssh remote_host fun
bashrc
functions work
Me di cuenta de que la ~/.bashrcestá solamente proceden cuando se especifica un comando como argumento para ssh. Esto tiene sentido: cuando sshse usa para iniciar un shell de inicio de sesión normal .profileo cuando .bash_profilese ejecuta (y .bashrcsolo se obtiene si uno de estos archivos lo hace explícitamente).
El principal beneficio que puedo ver al haber .bashrcobtenido 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 .bashrcsolo 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 rsho sshse 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, scpy sftpque usan shells remotos para transferir datos.
Resulta que el shell predeterminado del usuario remoto (como Bash) se inicia implícitamente cuando se usa el scpcomando. No se menciona esto en la página de manual, solo una mención que se scputiliza sshpara la transferencia de datos. Esto tiene la consecuencia de que si .bashrccontiene 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é scpy sftpfallar
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
ttyentrada 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/ sftpy 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 scpen 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 scpsolo permanece en un bucle, bloqueado read(2). Mientras tanto, después de que el perfil de shell se procesó en el lado remoto, scpse 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 .bashrcsolo son útiles para un shell interactivo, no cuando se ejecutan comandos remotos con rsho 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 scpo sftp. Salir después de verificar que el shell actual no es interactivo es el comportamiento más seguro para .bashrc.