Jak używać SSH do uruchamiania skryptu powłoki na zdalnym komputerze?


1220

Muszę uruchomić skrypt powłoki (Windows / Linux) na zdalnym komputerze.

Mam skonfigurowane SSH zarówno na komputerze A, jak i B. Mój skrypt znajduje się na komputerze A, który uruchomi część mojego kodu na komputerze zdalnym, komputerze B.

Komputery lokalne i zdalne mogą być systemem Windows lub Unix.

Czy istnieje sposób, aby to zrobić, używając Plink / SSH?


6
To samo pytanie dotyczy już serverfault: serverfault.com/questions/215756/… Więc prawdopodobnie nie ma sensu migrować tego pytania.
sleske,

9
Pytanie o awarię serwera nie ma jednak tylu odpowiedzi. Może to pytanie powinno je zastąpić.
Big McLargeHuge

5
Osobiście podoba mi się ta odpowiedź: unix.stackexchange.com/questions/87405/…
mikevoermans

27
Ponadto powinno to oczywiście dotyczyć tematu, ponieważ ssh jest podstawowym narzędziem do tworzenia oprogramowania.
static_rtti

4
Pytania dotyczące kawy i ssh nie mają takiego samego stopnia nie-tematyczności na temat SO. Zagłosowano na ponowne otwarcie.
Vincent Cantin

Odpowiedzi:


1192

Jeśli Maszyna A jest oknem Windows, możesz użyć Plink (część PuTTY ) z parametrem -m, a on wykona skrypt lokalny na zdalnym serwerze.

plink root@MachineB -m local_script.sh

Jeśli Maszyna A jest systemem uniksowym, możesz użyć:

ssh root@MachineB 'bash -s' < local_script.sh

Nie trzeba kopiować skryptu na zdalny serwer, aby go uruchomić.


11
czy korzystanie z tej -sopcji jest zaletą ? ta strona podręcznika prowadzi mnie do przekonania, że ​​przetworzy standardowe dane wejściowe po zakończeniu przetwarzania opcji, niezależnie od tego, czy -ssą używane, czy nie.
aeroNotAuto

78
W przypadku skryptu, który wymaga sudo, uruchom ssh root@MachineB 'echo "rootpass" | sudo -Sv && bash -s' < local_script.sh.
bradley.ayers

6
@ bradley.ayers pamiętaj, aby uruchomić polecenie z „spacją”, aby pominąć historię (PS musisz mieć, HISTCONTROL=ignoreboth or ignorespaceaby działało)
derenio

8
@ bradley.ayers w jakich sytuacjach potrzebujesz sudo, jeśli już logujesz się jako root?
Brian Schlenker,

21
@Agostino, możesz dodać następujące parametry: ssh root@MachineB ARG1="arg1" ARG2="arg2" 'bash -s' < local_script.sh Kredyty w pełni przejdź do odpowiedzi @chubbsondubs poniżej.
Yves Van Broekhoven,

632

To jest stare pytanie i odpowiedź Jasona działa dobrze, ale chciałbym dodać to:

ssh user@host <<'ENDSSH'
#commands to run on remote host
ENDSSH

Można tego również używać z poleceniami su i poleceniami, które wymagają wkładu użytkownika. (zwróć uwagę na 'uciekającego heredoka)

Edycja: Ponieważ ta odpowiedź ciągle się powiększa, dodałbym jeszcze więcej informacji do tego wspaniałego zastosowania heredoc:

Możesz zagnieżdżać polecenia za pomocą tej składni, i to jedyny sposób, w jaki wydaje się działać zagnieżdżanie (w rozsądny sposób)

ssh user@host <<'ENDSSH'
#commands to run on remote host
ssh user@host2 <<'END2'
# Another bunch of commands on another host
wall <<'ENDWALL'
Error: Out of cheese
ENDWALL
ftp ftp.secureftp-test.com <<'ENDFTP'
test
test
ls
ENDFTP
END2
ENDSSH

Możesz faktycznie rozmawiać z niektórymi usługami, takimi jak telnet, ftp itp. Pamiętaj jednak, że heredoc po prostu wysyła stdin jako tekst, nie czeka na odpowiedź między wierszami

Edycja: Właśnie dowiedziałem się, że możesz użyć wcięć wewnątrz kart, jeśli używasz <<-END!

ssh user@host <<-'ENDSSH'
    #commands to run on remote host
    ssh user@host2 <<-'END2'
        # Another bunch of commands on another host
        wall <<-'ENDWALL'
            Error: Out of cheese
        ENDWALL
        ftp ftp.secureftp-test.com <<-'ENDFTP'
            test
            test
            ls
        ENDFTP
    END2
ENDSSH

(Myślę, że to powinno działać)

Zobacz także http://tldp.org/LDP/abs/html/here-docs.html


4
możesz tymczasowo trochę dodać, dodając wiersze, takie jak: # $ (spać 5)
Olivier Dulac

50
zwróć uwagę, że przy pojedynczych cudzysłowach wokół terminatora ( <<'ENDSSH') ciągi nie zostaną rozwinięte, zmienne nie zostaną ocenione. Możesz także użyć <<ENDSSHlub, <<"ENDSSH"jeśli chcesz rozszerzenia.
maackle,

3
Expectmoże być używany, gdy trzeba zautomatyzować interaktywne polecenia, takie jak FTP.
programaths

5
Pamiętaj, że miałem Pseudo-terminal will not be allocated because stdin is not a terminal.wiadomość. -t -tAby tego uniknąć, należy użyć ssh z parametrami . Zobacz ten wątek w SO
Buzut

8
Jeśli próbujesz użyć składni << - 'END', upewnij się, że Twój ogranicznik zakończenia heredoc jest wcięty za pomocą TAB, a nie spacji. Zauważ, że kopiowanie / wklejanie z stackexchange da ci spacje. Zmień je na tabulatory, a funkcja wcięcia powinna działać.
fbicknel

249

Nie zapomnij także o zmianie zmiennych, jeśli chcesz je pobrać z hosta docelowego.

To mnie złapało w przeszłości.

Na przykład:

user@host> ssh user2@host2 "echo \$HOME"

wypisuje / home / user2

podczas

user@host> ssh user2@host2 "echo $HOME"

drukuje / home / user

Inny przykład:

user@host> ssh user2@host2 "echo hello world | awk '{print \$1}'"

drukuje poprawnie „cześć”.


2
Należy jednak pamiętać o następujących ssh user2@host 'bash -s' echo $HOME /home/user2 exit
kwestiach

1
Aby dodać, że w forpętlach działających w sshsesji zmienna pętli nie może być zmieniona.
AlexeyDaryin

1
W wielu sytuacjach rozsądnym sposobem naprawienia ostatniego przykładu byłoby ssh user2@host2 'echo hello world' | awk '{ print $1 }'np. Uruchomienie skryptu Awk lokalnie. Jeśli zdalne polecenie generuje ogromną ilość danych wyjściowych, oczywiście chcesz uniknąć kopiowania wszystkiego z powrotem na lokalny serwer. Nawiasem mówiąc, pojedyncze cudzysłowy wokół polecenia zdalnego pozwalają uniknąć ucieczki.
tripleee

151

Jest to rozszerzenie odpowiedzi YarekT, aby połączyć wbudowane polecenia zdalne z przekazywaniem zmiennych ENV z komputera lokalnego do zdalnego hosta, aby można było sparametryzować skrypty po stronie zdalnej:

ssh user@host ARG1=$ARG1 ARG2=$ARG2 'bash -s' <<'ENDSSH'
  # commands to run on remote host
  echo $ARG1 $ARG2
ENDSSH

Uznałem to za wyjątkowo pomocne, utrzymując wszystko w jednym skrypcie, dzięki czemu jest bardzo czytelny i łatwy w utrzymaniu.

Dlaczego to działa ssh obsługuje następującą składnię:

ssh użytkownik @ host komenda_zdalna

W bash możemy określić zmienne środowiskowe, które mają zostać zdefiniowane przed uruchomieniem polecenia w jednym wierszu:

ENV_VAR_1 = „wartość1” ENV_VAR_2 = „wartość2” bash -c „echo $ ENV_VAR_1 $ ENV_VAR_2”

Ułatwia to definiowanie zmiennych przed uruchomieniem polecenia. W tym przypadku echo to nasze polecenie, które uruchamiamy. Wszystko przed echem definiuje zmienne środowiskowe.

Łączymy więc te dwie funkcje z odpowiedzią YarekT, aby uzyskać:

ssh user @ host ARG1 = $ ARG1 ARG2 = $ ARG2 'bash -s' << 'ENDSSH' ...

W tym przypadku ustawiamy ARG1 i ARG2 na wartości lokalne. Wysyłanie wszystkiego po user @ host jako komenda_zdalna. Gdy zdalna maszyna wykonuje polecenie ARG1 i ARG2, są ustawiane wartości lokalne, dzięki ocenie lokalnego wiersza poleceń, która definiuje zmienne środowiskowe na zdalnym serwerze, a następnie wykonuje polecenie bash -s przy użyciu tych zmiennych. Voila


1
Zauważ, że jeśli chcesz przekazać argumenty takie jak -a, możesz użyć -. np. 'ssh user @ host - -a foo bar' bash -s '<script.sh'. A argumenty mogą również iść po przekierowaniu, np. „Ssh user @ host” bash -s '<script.sh - -a foo bar'.
gaoithe,

8
Jeśli którakolwiek z wartości env var zawiera spacje, użyj:ssh user@host "ARG1=\"$ARG1\" ARG2=\"$ARG2\"" 'bash -s' <<'ENDSSH'...
TalkLittle

Jak napisałem w innym komentarzu, celem tego -sjest użycie argumentów do skryptów pochodzących ze standardowego wejścia. To znaczy, równie dobrze możesz to pominąć, jeśli nie zamierzasz go używać. Jeśli go użyjesz, nie ma powodu, aby używać zmiennych środowiskowych:ssh user@host 'bash -s value1 value2' <<< 'echo "$@"'
JoL

104
<hostA_shell_prompt>$ ssh user@hostB "ls -la"

Spowoduje to wyświetlenie monitu o podanie hasła, chyba że skopiowałeś klucz publiczny użytkownika hosta do pliku autoryzowanych_kluczy w katalogu głównym katalogu użytkownika .ssh. Pozwoli to na uwierzytelnianie bez hasła (jeśli zostanie zaakceptowane jako metoda uwierzytelniania w konfiguracji serwera ssh)


3
Głosowałem na ciebie. To jest prawidłowe rozwiązanie. Oczywiście klucze muszą być chronione, ale można je również unieważnić tak samo jak hasło po stronie serwera.
willasaywhat

8
Nie sądzę, że to odpowiada na pytanie. Przykład pokazuje, jak uruchomić polecenie zdalne, ale nie sposób wykonania lokalnego skryptu na zdalnym komputerze.
Jason R. Coombs

Nie jesteś pewien, ale czy nie możesz przesłać skryptu na hostA, aby uruchomić go na hostB przy użyciu tej metody?
nevets1219

27

Zacząłem używać Fabric do bardziej wyrafinowanych operacji. Sieć szkieletowa wymaga języka Python i kilku innych zależności, ale tylko na komputerze klienckim. Serwer musi być tylko serwerem ssh. Uważam, że to narzędzie jest o wiele potężniejsze niż skrypty powłoki przekazywane do SSH i warte jest kłopotów z konfiguracją (szczególnie jeśli lubisz programować w Pythonie). Fabric obsługuje działające skrypty na wielu hostach (lub hostach niektórych ról), pomaga w wykonywaniu idempotentnych operacji (takich jak dodawanie wiersza do skryptu konfiguracyjnego, ale nie, jeśli już tam jest), i pozwala na budowę bardziej złożonej logiki (takiej jak Python język może zapewnić).


11

Spróbuj uruchomić ssh user@remote sh ./script.unx.


8
Działa to tylko wtedy, gdy skrypt znajduje się w domyślnym katalogu domowym na pilocie. Myślę, że pytanie brzmi: jak uruchomić skrypt przechowywany lokalnie na pilocie.
metasim

1
ssh nazwa użytkownika @ ip "chmod + x script.sh" <br/> ssh nazwa użytkownika @ ip "ścieżka do pliku sh na zdalnym hoście"
mani deepak



5

Używam tego do uruchomienia skryptu powłoki na zdalnym komputerze (testowany na / bin / bash):

ssh deploy@host . /home/deploy/path/to/script.sh

3
ssh user@hostname ".~/.bashrc;/cd path-to-file/;.filename.sh"

zdecydowanie zaleca się źródło pliku środowiska (.bashrc / .bashprofile / .profile). przed uruchomieniem czegoś na hoście zdalnym, ponieważ zmienne środowiskowe hosta docelowego i źródłowego mogą być niepoprawne.


To nie wyjaśnia, jak przenieść skrypt lokalny na zdalny host.
kirelagin

2

jeśli chcesz wykonać polecenie takie jak to temp=`ls -a` echo $temp w `` spowoduje błędy.

poniższe polecenie rozwiąże ten problem ssh user@host ''' temp=`ls -a` echo $temp '''


1

Odpowiedź tutaj ( https://stackoverflow.com/a/2732991/4752883 ) działa świetnie, jeśli próbujesz uruchomić skrypt na zdalnym komputerze z systemem Linux za pomocą plinklub ssh. Będzie działać, jeśli skrypt ma wiele wierszy linux.

** Jednak jeśli próbujesz uruchomić skrypt wsadowy znajdujący się na linux/windowskomputerze lokalnym , a twój komputer zdalny jest w stanie Windows, i składa się z wielu wierszy przy użyciu **

plink root@MachineB -m local_script.bat

nie zadziała.

Zostanie wykonana tylko pierwsza linia skryptu. Jest to prawdopodobnie ograniczenie plink.

Rozwiązanie 1:

Aby uruchomić wielowierszowy skrypt wsadowy (zwłaszcza jeśli jest stosunkowo prosty i składa się z kilku wierszy):

Jeśli oryginalny skrypt partii jest następujący

cd C:\Users\ipython_user\Desktop 
python filename.py

możesz połączyć linie razem za pomocą separatora „&&” w następujący sposób w local_script.batpliku: https://stackoverflow.com/a/8055390/4752883 :

cd C:\Users\ipython_user\Desktop && python filename.py

Po tej zmianie możesz uruchomić skrypt, jak wskazano tutaj przez @ JasonR.Coombs: https://stackoverflow.com/a/2732991/4752883 z:

`plink root@MachineB -m local_script.bat`

Rozwiązanie 2:

Jeśli skrypt wsadowy jest stosunkowo skomplikowany, może być lepiej użyć skryptu wsadowego, który zawiera polecenie plink, a także następujące czynności, jak wskazano tutaj @Martin https://stackoverflow.com/a/32196999/4752883 :

rem Open tunnel in the background
start plink.exe -ssh [username]@[hostname] -L 3307:127.0.0.1:3306 -i "[SSH
key]" -N

rem Wait a second to let Plink establish the tunnel 
timeout /t 1

rem Run the task using the tunnel
"C:\Program Files\R\R-3.2.1\bin\x64\R.exe" CMD BATCH qidash.R

rem Kill the tunnel
taskkill /im plink.exe

1

Ten skrypt bash robi ssh na docelowym komputerze zdalnym i uruchamia komendę na komputerze zdalnym, nie zapomnij zainstalować expect przed uruchomieniem go (na komputerze Mac brew install expect)

#!/usr/bin/expect
set username "enterusenamehere"
set password "enterpasswordhere"
set hosts "enteripaddressofhosthere"
spawn ssh  $username@$hosts
expect "$username@$hosts's password:"
send -- "$password\n"
expect "$"
send -- "somecommand on target remote machine here\n"
sleep 5
expect "$"
send -- "exit\n"

1
jest to świetne, jeśli musisz używać haseł ... jednak dla korzyści każdego, kto ogląda w domu, każde polecenie ssh powinno używać pary kluczy publicznych + prywatnych, a nie haseł ... raz na miejscu zaktualizuj swój serwer ssh, aby całkowicie wyłączał hasła
Scott Stensland

-1

Możesz użyć Runoverssh :

sudo apt install runoverssh
runoverssh -s localscript.sh user host1 host2 host3...

-s uruchamia skrypt lokalny zdalnie


Przydatne flagi:
-g użyj globalnego hasła dla wszystkich hostów (monit o jedno hasło)
-nużyj SSH zamiast sshpass, przydatny do uwierzytelniania z kluczem publicznym


-24

Najpierw skopiuj skrypt na maszynę B za pomocą scp

[użytkownik @ maszynaA] $ scp / ścieżka / do / skrypt użytkownik @ maszynaB: / home / użytkownik / ścieżka

Następnie uruchom skrypt

[użytkownik @ maszynaA] $ ssh użytkownik @ maszynaB "/ home / user / path / script"

Działa to, jeśli dałeś uprawnienia do wykonywania skryptu.


cześć, zastosowałem zalecaną procedurę, ale daje mi następujący błąd [oracle @ node1 ~] $ ssh oracle @ node2: ./ home / oracle / au / fs / conn.sh ssh: node2: ./ home / oracle / au / fs / conn.sh: Nazwa lub usługa nieznana [oracle @ node1 ~] $

„ssh oracle @ node2: ./ home / oracle / au / fs / conn.sh”? Zła linia poleceń, nazwa polecenia powinna być oddzielona od części użytkownik @ host spacją, a nie dwukropkiem.
bortzmeyer

5
Głosuję za tym, ponieważ to podstawowe twierdzenie, że nie można go uruchomić bez skopiowania, jest nieprawidłowe.
Jason R. Coombs

Byłoby pomocne, gdyby Jason dodał, dlaczego to nieprawda, zamiast po prostu powiedzieć o tym. Nieprzydatny.
Kris,

[użytkownik @ maszynaA] $ ssh root @ MachineB 'bash -s' </ machinea / path / to / script
Oleksii Kyslytsyn
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.