2013-03-06 25 views
6

Chciałbym wykonać kilka poleceń w sekwencji na komputerze zdalnym, a niektóre z późniejszych poleceń zależą od wcześniejszych. W możliwie najprostszy przykład uzyskać to:czy można używać zmiennych w zdalnych komendach ssh?

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 

Dla nieco informacji tła, co tak naprawdę chcę robić to kawałek razem ścieżką i uruchomić aplikację 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. 

ten sposób, za każdym razem, gdy jabref zostanie zaktualizowany do nowej wersji na serwerze, nie będę musiał ręcznie aktualizować ścieżki do pliku JAR. Plik wykonywalny jabref nie przyjmuje argumentów, ale uruchamia go z java -jar, dlatego muszę nieco żonglować ścieżką.

Obecnie mam listę poleceń w osobnym pliku skryptu i wywołać

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

który działa, ale ponieważ połączenie ssh jest już wewnątrz jednego pliku skryptu byłoby miło mieć wszystko razem.

Odpowiedz

6

Z pewną inspiracją od chepnera, mam teraz rozwiązanie, które działa, ale tylko wtedy, gdy zostanie wywołane z powłoki bash lub skryptu bash. To nie działa z tcsh.

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

podstawie tego, poniższy kod jest lokalny skrypt, który uruchamia JabRef na zdalnym serwerze (choć z X-Forwarding domyślnie i hasła uwierzytelnianie użytkownik nie może powiedzieć, że to zdalna):

#!/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 

i jest to 1-wierszowy skrypt load_module, ponieważ modulecmd ustawia zmienne środowiskowe i nie mogłem wymyślić jak to zrobić bez pozyskiwania skryptu.

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

ja również spojrzał na heredocs, zainspirowany How to use SSH to run a shell script on a remote machine? i http://tldp.org/LDP/abs/html/here-docs.html. Dobrą stroną jest to, że działa nawet z tcsh. Zrobiłem to działając z wiersza poleceń, ale nie wewnątrz skryptu. Prawdopodobnie łatwo to naprawić, ale mam teraz rozwiązanie, więc jestem szczęśliwy :-)

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

W tym przykładzie

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

abc jest ustawiony na zdalnej, więc powinno być jasne, dlaczego to nie jest ustawiony na komputerze lokalnym.

W następnym przykładzie

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

lokalna powłoka próbuje poszerzyć $abc w argumencie zanim zostanie kiedykolwiek wysyłane do zdalnego hosta. Nieznaczna modyfikacja będzie działać zgodnie z oczekiwaniami:

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

cudzysłowu zapobiec lokalnym powłokę próbuje poszerzyć $abc, a więc tekst dosłowny sprawia, że ​​do zdalnego hosta.


wreszcie zająć swoje prawdziwe pytanie, spróbuj tego:

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') 

Spowoduje to uruchomienie cudzysłowie jako polecenia na zdalnym serwerze, a wyjście dokładnie jeden ciąg: $jabref_dir. Ten ciąg jest przechwytywany i przechowywany w zmiennej na lokalnym hoście.

+0

dzięki, że postawiłem na dobrej drodze. Zapobieganie ekspansji za pomocą przecinków lub '\ $' było kluczowe. Okazuje się, że domyślną powłoką na serwerze było tcsh, i to był kolejny powód, dla którego 'abc = 2' nie działało. – craq

+0

Świetna odpowiedź. Używam Jenkinsa z wtyczką SSH Agent i działa jak urok. –