2013-03-06 18 views
6

Mi piacerebbe eseguire più comandi in sequenza su una macchina remota, e alcuni dei successivi comandi dipendono da quelli precedenti. Nel semplice esempio possibile ottengo questo:è possibile utilizzare le variabili nel comando ssh remoto?

ssh my_server "echo this is my_server; abc=2;" 
this is my_server 
abc=2: Command not found. 
ssh my_server "echo this is my_server; abc=2; echo abc is $abc" 
abc: undefined variable 

Per un po 'di informazioni di base, quello che in realtà voglio fare è mettere insieme un percorso e lanciare un'applicazione Java:

ssh my_server 'nohup sh -c "((echo this is my_server; jabref_exe=`which jabref`; jabref_dir=`dirname $jabref_exe`; java -jar $jabref_dir/../jabref.jar` $1 &/dev/null) &)"' & 
jabref_dir: Undefined variable. 

In questo modo, ogni volta che jabref viene aggiornato ad una nuova versione sul server, non dovrò aggiornare manualmente il percorso del file jar. L'eseguibile jabref non accetta argomenti, ma lo fa con java -jar, ed è per questo che devo destreggiarmi un po 'con il percorso.

Al momento ho l'elenco dei comandi in un file di script separato e chiamare

ssh my_server 'nohup sh -c "((my_script.sh &/dev/null) &)"' & 

che funziona, ma dal momento che la chiamata ssh è già dentro un file di script sarebbe bello avere tutto insieme.

risposta

6

Con una certa ispirazione da chepner, ora ho una soluzione che funziona, ma solo quando viene chiamata da una shell bash o da uno script di bash. Non funziona da tcsh.

ssh my_server "bash -c 'echo this is \$HOSTNAME; abc=2; echo abc is \$abc;'" 

Sulla base di questo, il codice qui sotto è uno script locale che gestisce JabRef su un server remoto (anche se con X-forwarding per impostazione predefinita e l'autenticazione senza password l'utente non può dire che è a distanza):

#!/bin/bash 
if [ -f "$1" ] 
then 
    fname_start=$(echo ${1:0:4}) 
    if [ "$fname_start" = "/tmp" ] 
    then 
     scp $1 my_server:$1 
     ssh my_server "bash -c 'source load_module jdk; source load_module jabref; java_exe=\$(which java); jabref_exe=\$(which jabref); jabref_dir=\$(echo \${jabref_exe%/bin/jabref});eval \$(java -jar \$jabref_dir/jabref.jar $1)'" & 
    else 
     echo input argument must be a file in /tmp. 
else 
    echo this function requires 1 argument 
fi 

e questo è lo script 1-riga load_module, dal momento che modulecmd imposta variabili d'ambiente e non sono riuscito a capire come farlo senza creare uno script.

eval `/path/to/modulecmd bash load $1`; 

Ho anche guardato heredocs, ispirato How to use SSH to run a shell script on a remote machine? e http://tldp.org/LDP/abs/html/here-docs.html. La parte bella è che funziona anche da tcsh. Ho ottenuto questo lavoro dalla riga di comando, ma non all'interno di uno script. Questo è probabilmente abbastanza facile da risolvere, ma ora ho una soluzione, quindi sono felice :-)

ssh my_server 'bash -s' << EOF 
echo this is \$HOSTNAME; abc=2; echo abc is \$abc; 
EOF 
6

In questo esempio

ssh my_server "echo this is my_server; abc=2;" 

abc è impostato sul lato remoto, quindi dovrebbe essere chiaro perché non è impostata sulla macchina locale.

Nel prossimo esempio,

ssh my_server "echo this is my_server; abc=2; echo abc is $abc" 

la shell locale tenta di espandersi $abc nell'argomento prima che sia mai inviato all'host remoto. Una leggera modifica potrebbe funzionare come previsto:

ssh my_server 'echo this is my_server; abc=2; echo abc is $abc' 

I singoli apici impediscono la shell locale da cercare di ampliare $abc, e così il testo letterale rende all'host remoto.


Per affrontare finalmente la tua vera domanda, provate questo:

jabref_dir=$(ssh my_server 'jabref_exe=$(which jabref); jabref_dir=$(dirname $jabref_exe); 
       java -jar $jabref_dir/../jabref.jar > /dev/null; echo $jabref_dir') 

Questo verrà eseguito la stringa citato come un comando sul server remoto, e l'uscita esattamente uno stringa: $jabref_dir. Quella stringa viene catturata e archiviata in una variabile sul tuo host locale.

+0

grazie, che mi ha messo sulla strada giusta. Prevenire l'espansione con virgolette o '\ $' era la chiave. Si scopre che la shell di default sul server era tcsh, e quello era un altro motivo per cui 'abc = 2' non funzionava. – craq

+0

Ottima risposta. Sto usando Jenkins con il plugin SSH Agent e funziona come un fascino. –

Problemi correlati