Perché l'esportazione di una variabile in una shell ssh stampa l'elenco delle variabili esportate?


17

Considera questo:

$ 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"

Perché l'esportazione di una variabile all'interno di una bash -csessione viene eseguita tramite ssh in quell'elenco di declare -xcomandi (l'elenco delle variabili attualmente esportate, per quanto posso dire)?

Eseguire la stessa cosa senza bash -cnon farlo:

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

Né succede se non export:

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

Ho testato questo da un computer Ubuntu da un altro (entrambi con bash 4.3.11) e su un computer Arch, lanciandosi su se stesso come mostrato sopra (bash versione 4.4.5).

Cosa sta succedendo qui? Perché l'esportazione di una variabile all'interno di una bash -cchiamata produce questo output?


Questo non risponde alla domanda, ma l'output è il risultato dell'esecuzione export. Zsh fa la stessa cosa.
Stephen Kitt,

@StephenKitt sì, lo so export, sto cercando di capire cosa sta succedendo. Modificherò per chiarire che ciò accade solo durante l'esportazione.
terdon

Ah OK, avrei letto "l'elenco delle variabili attualmente esportate, per quanto posso dire" nel senso che non sapevi da dove venisse l'output.
Stephen Kitt,

@StephenKitt Voglio dire, non sono sicuro che sia ogni variabile esportata o un sottoinsieme specifico o cosa. Oh! Vuoi dire che è l'output di exportRun da solo? Che non avevo capito.
terdon

Si noti che foo=barnon appare nell'elenco.
Delta,

Risposte:


31

Quando esegui un comando ssh, viene eseguito chiamando il tuo$SHELL con il -cflag:

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

Così, ssh remote_host "bash -c foo" eseguirà effettivamente:

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

Ora, poiché il comando che stai eseguendo ( export foo=bar) contiene spazi e non è correttamente citato per formare un intero, exportviene preso come comando da eseguire e il resto viene salvato nella matrice dei parametri posizionali. Ciò significa che exportviene eseguito e gli foo=barviene passato come$0 . Il risultato finale è lo stesso della corsa

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

Il comando corretto sarebbe:

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

9

ssh concatena gli argomenti con spazi e fa interpretare la shell di login dell'utente remoto, quindi in:

ssh localhost bash -c 'export foo=bar'

ssh chiede alla shell remota di interpretare il file

bash -c export foo=bar

comando (in effetti, se l'host remoto è simile a Unix, eseguirà la shell remota con the-shell,-c e bash -c export foo=barcome argomenti).

La maggior parte dei gusci interpreteranno quella linea di comando come in esecuzione il bashcomando con bash, -c, exporte foo=barcome argomenti (in modo da eseguire exportmentre $0contiene foo=bar), mentre che ci si vuole che venga eseguito con bash, -ceexport foo=bar come argomenti.

Per questo, dovresti usare una riga di comando come:

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

(o:

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

per quello che conta) quindi il:

bash -c 'export foo=bar'

la riga di comando deve essere passata alla shell remota. Quella linea di comando sarebbe stata interpretata dalla maggior parte dei gusci come eseguire il bashcomando con bash, -ce export foo=barcome argomenti. Si noti che l'utilizzo

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

non funzionerebbe se la shell di accesso dell'utente remoto fosse rco, esad esempio, in cui "non sia presente un operatore di quotazione speciale. Le virgolette singole sono gli operatori di quotazione più portatili (sebbene ci siano alcune variazioni nel modo in cui vengono interpretate tra le shell, vedere Come eseguire un comando semplice arbitrario su ssh senza conoscere la shell di accesso dell'utente remoto? Per ulteriori informazioni).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.