Wie führe ich ein lokales Bash-Skript auf entfernten Rechnern über ssh aus?

51

Ich suche nach einer Möglichkeit, die Konfiguration von einem zentralen Computer auf mehrere Remotecomputer zu übertragen, ohne dass auf den Remotecomputern etwas installiert werden muss.

Das Ziel ist es, etwas zu tun, wie Sie es mit Werkzeugen wie tun würden cfengine, aber auf einer Reihe von Maschinen, auf denen keine Agenten eingerichtet sind. Dies ist möglicherweise eine gute Technik zum Einrichten cfagentauf einer Reihe vorhandener Remotecomputer.

tremoloqui
quelle
Ähnlich wie auf SO: stackoverflow.com/q/305035/435605
AlikElzin-kilaka
1
Die eigentliche Frage hat 23 Upvotes, wobei das Duplikat auf SO 55: P
MoJo

Antworten:

55

Sie können ein Skript übergeben und es vorübergehend ausführen lassen, indem Sie es in eine Pipeline einfügen und eine Shell ausführen.

z.B

echo "ls -l; echo 'Hello World'" | ssh me@myserver /bin/bash

Natürlich "ls -l; echo 'Hello World'"könnte das Teil durch ein Bash-Skript ersetzt werden, das in einer Datei auf dem lokalen Computer gespeichert ist.

z.B

cat script.sh | ssh me@myserver /bin/bash

Prost!

tremoloqui
quelle
2
Wie lasse ich dies als sudo auf dem fernen System laufen.eg Wenn ich auf dem fernen Server angemeldet wäre, würde ich dies normalerweise als sudo -u testuser script.sh
Sharjeel
Was ist, wenn das Skript, das ich aufrufe, Benutzerinteraktionen beinhaltet?
Abhimanyu Srivastava
20

Es gibt verschiedene Möglichkeiten, dies zu tun.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

Nummer 3 ist mein bevorzugter Weg, es erlaubt interaktive Befehle zB su -S service nginx restart

(Bei Verwendung von Nummer 1 wird der Rest des Skripts als Eingabe für die Kennwortfrage verwendet su -S.)

Paul Verschoor
quelle
4
Bezüglich der Ausführung eines lokalen Skripts auf einem Remote-Computer - Gibt es eine Möglichkeit, eine Variable als Argument an den Remote-Computer zu senden? dh zusammen mit dem Skript möchte ich eine Variable (mit mehreren Zeilen) als Argument an die entfernte Maschine senden. Das Skript beabsichtigt dann, die Variable zu verwenden.
13

Ich würde Pythons Stoff für diesen Zweck empfehlen:

#!/usr/bin/python
# ~/fabfile.py

from fabric_api import *

env.hosts = ['host1', 'host2']
def deploy_script():
    put('your_script.sh', 'your_script.sh', mode=0755)
    sudo('./your_script.sh')

# from shell
$ fab deploy_script

Sie sollten in der Lage sein, die oben genannten zu verwenden, um loszulegen. Konsultieren Sie die ausgezeichnete Dokumentation von Fabric , um den Rest zu erledigen. Als Ergänzung ist es durchaus möglich, Ihr Skript vollständig in Fabric zu schreiben - es ist kein Kopieren erforderlich. Es ist jedoch zu beachten, dass Sie zum Ändern des Skripts auf allen Computern nur die lokale Kopie bearbeiten und erneut bereitstellen müssen. Darüber hinaus können Sie mit etwas mehr als der grundlegenden Verwendung der API das Skript basierend auf dem Host, auf dem es derzeit ausgeführt wird, und / oder anderen Variablen ändern. Es ist eine Art pythonischer Expect.

Sam Halicke
quelle
Ich glaube nicht, dass dies genau die Frage beantwortet, aber ich mag die Idee und ich könnte Fabric als nützliches Werkzeug ansehen.
Tremoloqui
1
@tremoloqui Fabric ist ein Python-Wrapper für ssh. Auf den Zielcomputern muss nichts installiert werden. Speichern Sie das Skript, das übertragen wird. Was, wenn es als eine Reihe von Fabric-Befehlen (mit runund sudo) umgeschrieben wird, nicht einmal benötigt wird.
Izkata,
5

Genau dafür wird Ansible verwendet. Es gibt keinen Agenten, Sie müssen lediglich eine Textdatei mit dem Namen erstellen:

/etc/ansible/hosts

mit Inhalten, die ungefähr so ​​aussehen:

[webhosts]
web[1-8]

Dies würde angeben, dass sich die Maschinen "web1, web2 ... web8" in der Gruppe "webhosts" befinden. Dann können Sie Dinge tun wie:

ansible webhosts -m service -a "name=apache2 state=restarted" --sudo

Starten Sie den Apache2-Dienst auf allen Ihren Computern mit sudo neu.

Sie können im laufenden Betrieb folgende Befehle ausführen:

ansible webhosts -m shell -a "df -h"

Oder Sie können ein lokales Skript auf dem Remote-Computer ausführen:

ansible webhosts -m script -a "./script.sh"

Sie können auch ein Playbook mit einer vollständigen Konfiguration erstellen (Details finden Sie in der Dokumentation), mit der Ihre Server kompatibel sein sollen, und es bereitstellen:

ansible-playbook webplaybook.yml

Grundsätzlich können Sie es als Befehlszeilentool zum Ausführen von Befehlen auf mehreren Servern verwenden und seine Verwendung nach Belieben zu einem vollständigen Konfigurationstool erweitern.

seumasmac
quelle
3
Ich mag Ansible genauso gern wie den nächsten, aber wenn er nach einem Drehbuch fragt, dann hat Ansible ein wirklich nettes Drehbuchmodul :ansible webhosts -m script script.sh
ptman
1
Alle anderen Antworten beinhalten ein Bash-Skript, aber es ist nicht das, wonach er speziell gefragt hat. Er hat nur gesagt, dass er die Konfiguration auf entfernte Maschinen schiebt. Aber eine gute Erwähnung des Skriptmoduls :)
seumasmac
Bitte stimmen Sie diese Antwort ab! Dies ist der Weg, um es zu tun!
Küken
@ptman Mir ist gerade erst aufgefallen, dass er in der Frage kein Skript erwähnt, aber im Titel! Es tut uns leid. Ich habe aktualisiert.
Seumasmac
3

Wie in dieser Antwort erklärt , können Sie heredoc verwenden :

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

Mit heredoc muss man vorsichtig sein, da es nur Text sendet, aber nicht wirklich auf die Antwort wartet. Das heißt, es wird nicht auf die Ausführung Ihrer Befehle warten.

BЈовић
quelle
1

Die Antwort hier ( https://stackoverflow.com/a/2732991/4752883 ) funktioniert hervorragend, wenn Sie versuchen, ein Skript auf einem entfernten Linux-Computer mit plinkoder auszuführen ssh. Es funktioniert, wenn das Skript mehrere Zeilen enthält linux.

** Wenn Sie jedoch versuchen, ein Batch-Skript auszuführen, das sich auf einem lokalen linux/windowsComputer befindet und sich auf Ihrem Remotecomputer befindet Windowsund aus mehreren Zeilen besteht, die Folgendes verwenden: **

plink root@MachineB -m local_script.bat

es wird nicht funktionieren.

Nur die erste Zeile des Skripts wird ausgeführt. Dies ist wahrscheinlich eine Einschränkung von plink.

Lösung 1:

So führen Sie ein mehrzeiliges Stapelskript aus (insbesondere, wenn es relativ einfach ist und aus wenigen Zeilen besteht):

Wenn Ihr ursprüngliches Stapelskript wie folgt lautet

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

Sie können die Zeilen mithilfe des Trennzeichens "&&" wie folgt in Ihrer local_script.batDatei kombinieren : https://stackoverflow.com/a/8055390/4752883 :

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

Nach dieser Änderung können Sie das Skript wie hier von @ JasonR.Coombs beschrieben ausführen: https://stackoverflow.com/a/2732991/4752883

Lösung 2:

Wenn Ihr Stapelskript relativ kompliziert ist, ist es möglicherweise besser, ein Stapelskript zu verwenden, das den Befehl plink sowie die folgenden Elemente enthält, auf die hier von @Martin https://stackoverflow.com/a/32196999/4752883 hingewiesen wird :

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
alpha_989
quelle
0

Warum nicht einfach zuerst das Skript kopieren und dann ausführen?

scp your_script.sh the_server:
ssh the_server "chmod +x your_script.sh; ./your_script.sh"

Natürlich solltest du darauf achten, dass du es nicht an einen Ort hochlädst, an dem es für die ganze Welt beschreibbar ist, damit niemand anders damit herumspielen kann, bevor du es ausführst (möglicherweise als root).

Dave Vogt
quelle
1
Der Grund, warum ich das Skript nicht hochladen möchte, ist, dass es nicht verwaltet werden muss und die von Ihnen erwähnten Risiken aufweist. Außerdem scheint es mir einfacher zu sein als der mehrstufige Vorgang des Hochladens, Verarbeitens und (optionalen) Löschens.
tremoloqui
0

Schreiben Sie das Skript so um, dass jedem darin enthaltenen Befehl bereits das Präfix ssh vorangestellt ist und ein Hostname / eine IP-Adresse oder eine Liste davon als Argument an das Skript übergeben wird (vorausgesetzt, Sie haben eine kennwortlose / ssh-Agent-Schlüsselauthentifizierung eingerichtet). Möglicherweise sind einige Arbeiten erforderlich, um Fehler- / Rückgabecodes von den Remotebefehlen korrekt zurückzugeben.

Rackandboneman
quelle
0

Wenn das Skript nicht zu groß ist und Sie bash oder ksh verwenden ...

ssh vm24 -t bash -c "$(printf "%q" "$(< shell-test.sh )")"

Sowohl stdin als auch stdout funktionieren ordnungsgemäß, das Skript ist jedoch auf die Argumentgröße beschränkt (normalerweise ca. 100 KB). Argumente für das Skript funktionieren möglicherweise am Ende der Zeile, möglicherweise nach einem zusätzlichen "-" Argument. Das "-t" zum Zuweisen einer Pty ist optional.

Achtung: Dies verwirrt die Bash-Vervollständigung. Drücke nicht die Tabulatortaste.

user3710044
quelle