¿Por qué exportar una variable en un shell ssh imprime la lista de variables exportadas?

17

Considera esto:

$ ssh localhost bash -c 'export foo=bar'
terdon@localhost's password: 
declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
declare -x HOME="/home/terdon"
declare -x LOGNAME="terdon"
declare -x MAIL="/var/spool/mail/terdon"
declare -x OLDPWD
declare -x PATH="/usr/bin:/bin:/usr/sbin:/sbin"
declare -x PWD="/home/terdon"
declare -x SHELL="/bin/bash"
declare -x SHLVL="2"
declare -x SSH_CLIENT="::1 55858 22"
declare -x SSH_CONNECTION="::1 55858 ::1 22"
declare -x USER="terdon"
declare -x XDG_RUNTIME_DIR="/run/user/1000"
declare -x XDG_SESSION_ID="c5"
declare -x _="/usr/bin/bash"

¿Por qué la exportación de una variable dentro de un bash -cplazo de sesión a través de ssh resultado en esa lista de declare -xcomandos (la lista de variables actualmente exportados, por lo que yo puedo decir)?

Ejecutar lo mismo sin el bash -cno hace eso:

$ ssh localhost  'export foo=bar'
terdon@localhost's password: 
$

Tampoco sucede si no lo hacemos export:

$ ssh localhost bash -c 'foo=bar'
terdon@localhost's password: 
$ 

Probé esto enviando mensajes de una máquina Ubuntu a otra (ambos ejecutando bash 4.3.11) y en una máquina Arch, enviando mensajes a sí mismo como se muestra arriba (versión bash 4.4.5).

¿Que está pasando aqui? ¿Por qué exportar una variable dentro de una bash -cllamada produce esta salida?

terdon
fuente
Esto no responde la pregunta, pero el resultado es el resultado de la ejecución export. Zsh hace lo mismo.
Stephen Kitt
@StephenKitt sí, lo sé export, estoy tratando de entender qué está pasando. Lo editaré para aclarar que esto solo ocurre al exportar.
terdon
Ah, ok, leí "la lista de variables actualmente exportadas, por lo que puedo decir", lo que significa que no sabías de dónde venía la salida.
Stephen Kitt
@StephenKitt Quiero decir que no estoy seguro de si esa es cada variable exportada o un subconjunto específico o qué. Oh! ¿Quieres decir que es el resultado de exportcorrer solo? Eso no lo había entendido.
terdon
Tenga en cuenta que foo=barno aparece en la lista.
deltab

Respuestas:

31

Cuando ejecuta un comando ssh, se ejecuta llamando a $SHELLcon la -cbandera:

-c    If the -c option is present, then commands are read from 
      the first non-option argument command_string.  If there  are
      arguments  after the command_string, the first argument is 
      assigned to $0 and any remaining arguments are assigned to
      the positional parameters.  

Entonces, en ssh remote_host "bash -c foo"realidad se ejecutará:

/bin/your_shell -c 'bash -c foo'

Ahora, debido a que el comando que está ejecutando ( export foo=bar) contiene espacios y no se cita correctamente para formar un todo, exportse toma como el comando a ejecutar y el resto se guarda en la matriz de parámetros posicionales. Esto significa que exportse ejecuta y foo=barse le pasa como $0. El resultado final es el mismo que correr

/bin/your_shell -c 'bash -c export'

El comando correcto sería:

ssh remote_host "bash -c 'export foo=bar'"
xhienne
fuente
9

ssh concatena los argumentos con espacios y hace que el shell de inicio de sesión del usuario remoto lo interprete, así que en:

ssh localhost bash -c 'export foo=bar'

ssh está pidiendo al shell remoto que interprete el

bash -c export foo=bar

de comandos (en efecto, si el host remoto es similar a Unix, pondrá en funcionamiento el shell remoto con the-shell, -cy bash -c export foo=barcomo argumentos).

La mayoría de las conchas interpretarán que la línea de comandos como ejecutar el bashcomando con bash, -c, exporty foo=barcomo argumentos (para correr exportmientras que $0contiene foo=bar), mientras que le desea que se ejecute con bash, -cy export foo=barcomo argumentos.

Para eso, necesitaría usar una línea de comando como:

ssh localhost "bash -c 'export foo=bar'"

(o:

ssh localhost bash -c \'export foo=bar\'

para eso importa) así que:

bash -c 'export foo=bar'

la línea de comando se pasa al shell remoto. Esa línea de comandos sería interpretado por la mayoría de conchas como ejecutar el bashcomando con bash, -cy export foo=barcomo argumentos. Tenga en cuenta que usando

ssh localhost 'bash -c "export foo=bar"'

no funcionaría si el shell de inicio de sesión del usuario remoto fuera rcoes por ejemplo, "no fuera un operador de cotización especial. Las comillas simples son los operadores de comillas más portátiles (aunque hay alguna variación en cómo se interpretan entre shells, consulte ¿Cómo ejecutar un comando simple arbitrario sobre ssh sin conocer el shell de inicio de sesión del usuario remoto? Para obtener más información).

Stéphane Chazelas
fuente