¿Por qué un comando remoto SSH obtiene menos variables de entorno que cuando se ejecuta manualmente? [cerrado]

239

Tengo un comando que funciona bien si ssh a una máquina y lo ejecuto, pero falla cuando intento ejecutarlo usando un comando ssh remoto como:

ssh user@IP <command>

La comparación de la salida de "env" usando ambos métodos resulta en diferentes entornos. Cuando inicio sesión manualmente en la máquina y ejecuto env, obtengo muchas más variables de entorno que cuando ejecuto:

ssh user@IP "env"

¿Alguna idea de por qué?

Tom Feiner
fuente
30
¿Por qué exactamente esta pregunta está cerrada como fuera de tema?
jottr
13
Probablemente porque no está relacionado con la programación. Debería haberse movido a Superusuario en lugar de cerrado.
Daniel H
8
bashno es un lenguaje de script?
Dan Nissenbaum
En Debian 8 tuve que cambiar el shell para bash en / etc / passwd por alguna razón. Incluso reconfigurar el guión para dejar / bin / sh apuntar a bash no ayudó.
user1050755

Respuestas:

173

Hay diferentes tipos de conchas. El shell de ejecución del comando SSH es un shell no interactivo, mientras que su shell normal es un shell de inicio de sesión o un shell interactivo. La descripción sigue, de man bash:

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

       Un shell interactivo es uno iniciado sin opción
       argumentos y sin la opción -c cuya entrada estándar
       y el error están conectados a los terminales (según lo determinado
       por isatty (3)), o uno comenzó con la opción -i. PS1 es
       set y $ - incluye i si bash es interactivo, permitiendo un
       script de shell o un archivo de inicio para probar este estado.

       Los siguientes párrafos describen cómo bash ejecuta su
       archivos de inicio Si alguno de los archivos existe pero no puede ser
       leer, bash informa un error. Tildes se expanden en el archivo
       nombres como se describe a continuación en Tilde Expansion en el
       Sección de expansión.

       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_login y ~ / .profile, en ese
       orden, y lee y ejecuta comandos del primero
       eso existe y es legible. La opción --noprofile puede
       ser utilizado cuando se inicia el shell para inhibir este comportamiento
       ior.

       Cuando sale un shell de inicio de sesión, bash lee y ejecuta comandos
       del archivo ~ / .bash_logout, si existe.

       Cuando un shell interactivo que no es un shell de inicio de sesión es
       iniciado, bash lee y ejecuta comandos desde ~ / .bashrc,
       si ese archivo existe Esto puede inhibirse mediante el uso de
       - opción opcional. La opción de archivo --rcfile forzará bash
       leer y ejecutar comandos desde un archivo en lugar de
       ~ / .bashrc.

       Cuando bash se inicia de forma no interactiva, para ejecutar un shell
       script, por ejemplo, busca la variable BASH_ENV en
       el medio ambiente, expande su valor si aparece allí,
       y usa el valor expandido como el nombre de un archivo para leer
       y ejecutar Bash se comporta como si el siguiente comando
       fueron ejecutados:
              si [-n "$ BASH_ENV"]; luego . "$ BASH_ENV"; fi
       pero el valor de la variable PATH no se usa para buscar
       para el nombre del archivo.

Vinko Vrsalovic
fuente
77
Gran respuesta, este fue exactamente el problema, las variables de entorno necesarias residían en / etc / bashrc, que no se obtiene en modo no interactivo. Moverlos a / etc / profile resolvió el problema. ¡Muchas gracias!
Tom Feiner,
1
Esta respuesta es solo una solución parcial. Aquí hay más información: agregue una variable de entorno diferente (por ejemplo, exportar SOURCED_SYSTEM_ETC_BASHRC) a los diversos archivos que se obtienen: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Luego busque esa variable única en la salida de Jenkins. En mi caso, actualicé / etc / bashrc para contener 'export SOURCED_SYSTEM_ETC_BASHRC = yes', y esa variable apareció en el registro de Jenkins para el nodo. Entonces, en mi caso, para establecer variables de entorno para esclavos jenkins, deben ir a / etc / bashrc. El inicio de sesión ssh de Jenkins solo se obtuvo / etc / bashrc.
Codificador Roadie
Corrección: quise decir /etc/bash.bashrc, no / etc / bashrc.
Codificador Roadie
37
Eso es todo un muro de texto, creo que valdría la pena destacar que ssh user@host "bash --login -c 'command arg1 ...'"hará que el shell remoto configure el entorno de inicio de sesión. La sección que citó menciona --loginpero sería fácil pasar por alto esto.
codebeard
Gracias por esta publicación, solía ssh <ssh options> <IP> bash --login my_script.shejecutar un script en la máquina remota, funcionaba bien y me permitía usar con éxito los JAVA_HOME
entornos
117

¿Qué hay de obtener el perfil antes de ejecutar el comando?

ssh user@host "source /etc/profile; /path/script.sh"

Puede que le resulte mejor para cambiar eso a ~/.bash_profile, ~/.bashrco lo que sea.

(Como aquí (linuxquestions.org) )

Ian Vaughan
fuente
1
Tenía este problema, esta solución funcionó muy bien.
Sam152
10
¡Tener que escribir siempre código adicional solo para generar el entorno es ridículo!
Michael
44
Rara vez se teclean repetidamente este tipo de cosas, normalmente estaría dentro de un script, y como tal, no importa cuánto "código extra" haya, siempre que funcione: tm:
Ian Vaughan
1
Si obtengo tanto / etc / profile como ~ / .bash_profile (para obtener adiciones del usuario a la ruta) funciona, pero es feo. Debe haber una manera más fácil de decirle al comando (en mi caso xterm) que use el inicio de sesión "interactivo" y termine con la ruta completa específica del usuario en la máquina remota.
Jess
ssh $ 1 "source ~ / .bashrc; ~ / temp_unix.sh" Aquí temp_unix.sh ha exportado MANI_HOME = "mani deepak" pero no está funcionando.
mani deepak
90

El entorno de Shell no se carga cuando se ejecuta el comando ssh remoto. Puede editar el archivo de entorno ssh:

vi ~/.ssh/environment

Su formato es:

VAR1=VALUE1
VAR2=VALUE2

Además, verifique la sshdconfiguración para la PermitUserEnvironment=yesopción.

dpedro
fuente
1
¡perfección! +100 si pudiera :)
Dexter
VisualGDB estaba fallando con el error "bash: gcc: comando no encontrado" y esta solución lo rectificó.
KalenGi
fantástico. Ojalá hubiera sabido esto hace años.
gravitación
Esta es la respuesta perfecta!
Jirapong
1
@ pg2455 aunque no siempre puede configurar sshd en su servidor (o no quiere habilitarlo para todos), aún puede editar su entorno de usuario
dpedro
63

Tuve un problema similar, pero al final descubrí que ~ / .bashrc era todo lo que necesitaba.

Sin embargo, en Ubuntu, tuve que comentar la línea que deja de procesar ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return
tomaszbak
fuente
8
Alternativamente, puede colocar todo su código "no interactivo" por encima de esa línea.
machineghost
hermoso, me ahorró mucho tiempo :) gracias
Lance Pollard
Gracias. Simplemente agregue que el archivo con la declaración de devolución se puede encontrar en /etc/bash.bashrc.
adarshr
¿Hay alguna forma de omitir este código en el servidor sin cambiarlo?
Yoni
Pasé mucho tiempo tratando de entender por qué mi guión no funcionaba. ¿Quién pensó que era una buena idea poner estas líneas en el .bashrc?
Sharcoux
4

Encontré que una solución fácil para este problema era agregar la fuente / etc / profile a la parte superior del archivo script.sh que estaba tratando de ejecutar en el sistema de destino. En los sistemas aquí, esto provocó que las variables de entorno que script.sh necesitaba configurar como si se ejecutaran desde un shell de inicio de sesión.

En una de las respuestas anteriores se sugirió que se utilizara ~ / .bashr_profile, etc. No pasé mucho tiempo en esto, pero el problema con esto es que si envía un mensaje a un usuario diferente en el sistema de destino que el shell en el sistema fuente desde el que inicia sesión, me pareció que esto causa que el usuario del sistema fuente nombre que se utilizará para el ~.

Arrojar
fuente
¡Perfecto! Buena solución de una línea para el problema.
corpico
3

Simplemente exporte las variables de entorno que desee sobre la comprobación de un shell no interactivo en ~ / .bashrc.

Michael MacDonald
fuente