Por que exportar uma variável em um shell ssh imprime a lista de variáveis ​​exportadas?

17

Considere isto:

$ 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 que exportar uma variável dentro de uma bash -csessão executada via ssh resulta nessa lista de declare -xcomandos (a lista de variáveis ​​atualmente exportadas, até onde eu sei)?

Executar a mesma coisa sem o bash -cnão faz isso:

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

Nem acontece se não o fizermos export:

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

Eu testei isso sshing de uma máquina Ubuntu para outra (ambas executando o bash 4.3.11) e em uma máquina Arch, sshing para si mesma, como mostrado acima (versão do bash 4.4.5).

O que está acontecendo aqui? Por que exportar uma variável dentro de uma bash -cchamada produz essa saída?

terdon
fonte
Isso não responde à pergunta, mas a saída é o resultado da execução export. Zsh faz a mesma coisa.
Stephen Kitt
@StephenKitt sim, eu sei que exportestou tentando entender o que está acontecendo. Vou editar para esclarecer que isso só acontece na exportação.
terdon
Ah, ok, eu li "a lista de variáveis ​​exportadas atualmente, tanto quanto posso dizer", o que significa que você não sabia de onde vinha a saída.
Stephen Kitt
@StephenKitt, quero dizer, não tenho certeza se essa é uma variável exportada ou um subconjunto específico ou o quê. Oh! Você quer dizer que é a saída de exportcorrer sozinho? Isso eu não tinha entendido.
terdon
Observe que foo=barnão aparece na lista.
deltab

Respostas:

31

Quando você executa um comando ssh, ele é executado chamando seu $SHELLcom o -csinalizador:

-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.  

Então, ssh remote_host "bash -c foo"na verdade , será executado:

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

Agora, como o comando que você está executando ( export foo=bar) contém espaços e não é adequadamente citado para formar um todo, ele exporté tomado como o comando a ser executado e o restante é salvo na matriz de parâmetros posicionais. Isso significa que exporté executado e foo=barpassado para ele como $0. O resultado final é o mesmo que correr

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

O comando correto seria:

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

ssh concatena os argumentos com espaços e faz com que o shell de login do usuário remoto o interprete, em:

ssh localhost bash -c 'export foo=bar'

ssh está pedindo ao shell remoto para interpretar o

bash -c export foo=bar

de comando (na verdade, se o host remoto é Unix-like, ele irá executar o shell remoto com the-shell, -ce bash -c export foo=barcomo argumentos).

A maioria das conchas irá interpretar essa linha de comando como executar o bashcomando com bash, -c, exporte foo=barcomo argumentos (para executar exportenquanto $0contém foo=bar), enquanto você ia querer que ele seja executado com bash, -ce export foo=barcomo argumentos.

Para isso, você precisará usar uma linha de comando como:

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

(ou:

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

para esse assunto) de modo que:

bash -c 'export foo=bar'

linha de comando seja passada para o shell remoto. Essa linha de comando seria interpretado pela maioria das conchas como executar o bashcomando com bash, -ce export foo=barcomo argumentos. Observe que usar

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

não funcionaria se o shell de login do usuário remoto estivesse rcou, espor exemplo, onde "não fosse um operador de cotação especial. As aspas simples são os operadores de cotação mais portáteis (embora exista alguma variação em como eles são interpretados entre shells, consulte Como executar um comando simples e arbitrário sobre o ssh sem conhecer o shell de login do usuário remoto? Para saber mais sobre isso).

Stéphane Chazelas
fonte