Remote-Ausführung eines Shell-Skripts, das eine lokale Datei als Eingabeparameter verwendet

1

Mit Linux, Bash und OpenSSH kann ich ein Shellskript auf einem Remote-Host auf mindestens drei Arten ausführen:

# Method 1: Script is never stored on the remote host
ssh <username>@<hostname> 'bash -s' < myShellScript

# Method 2: Script is permanently stored on the remote host
ssh <username>@<hostname> 'myShellScript'

# Method 3: Copy script to the remote host, execute it, and delete it
scp myShellScript <username>@<hostname>:~
ssh <username>@<hostname> 'myShellScript; rm -f myShellScript'

Ich ziehe Methode 1 der Methode 2 vor, da sie die Verbreitung von Skriptkopien und die damit verbundenen Wartungsprobleme verhindert.

Ich ziehe Methode 1 der Methode 3 vor, weil sie schneller und in der Regel "sauberer" ist, als das Skript zu kopieren und zu löschen.

Aber es gibt ein Problem, das ich umgehen muss, um mein Ziel zu erreichen bei Methode 1 bleiben myShellScript ist von dieser Form:

#!/bin/bash

# Do stuff...
myProgram input myProgramInputFile
# Do more stuff...

Hier, meinProgramm ist ein Standard-Dienstprogramm, das auf allen Remote-Hosts verfügbar ist, mit denen ich möglicherweise interagieren möchte. Jedoch, myProgramInputFile ist eine reguläre Datei, die nur auf meinem lokalen Computer vorhanden ist. Es ist auf keinem der entfernten Hosts vorhanden.

Ich möchte "bündeln" können myShellScript und myProgramInputFile in ein nettes "Paket", das auf dem Remote-Host über SSH ausgeführt wird, ohne explizit irgendetwas im Remote-Dateisystem zu speichern, entweder dauerhaft oder temporär. Ist das möglich?

Dave
quelle
Können Sie Dateien beispielsweise über NFS oder ähnliches freigeben?
Eric Renouf
Sehen diese Frage . Ihre Methode 1 kann sich gegen Ihre Erwartungen verhalten, wenn myShellScript macht bestimmte "Sachen". Kennen Sie die Fallstricke, wenn Sie diese Methode weiterhin verwenden.
Kamil Maciorowski

Antworten:

1

Ich würde lieber wenigstens kopieren myProgramInputFile ( Methode 3 wie); Ich denke, es wäre robuster. Es gibt jedoch eine Möglichkeit, damit es mit der Sohle funktioniert Methode 1 .



Mein Ansatz

Ich empfehle Ihnen, ein (lokales) Skript zu erstellen, das die entsprechende Datei auf die Remote-Seite kopiert, die Ausführung auslöst und anschließend bereinigt.

Wir benötigen drei lokale Dateien: myLocalScript (ausführbar), myRemoteScript und myProgramInputFile.

Der Inhalt von myLocalScript:

#!/bin/bash

# step 1: storing command line arguments to meaningful names
ssh_command="ssh $1"
script="$2"
input="$3"

# step 2: creating remote temporary file
remote_input=$($ssh_command 'mktemp')

# step 3: copying the content of local input file to the remote temporary file
cat "$input" | $ssh_command "cat > \"$remote_input\""

# step 4: sourcing the script to the remote side
$ssh_command "input=\"$remote_input\" bash -s" < "$script"

# step 5: removing the remote temporary file
$ssh_command "rm \"$remote_input\""

myRemoteScript sieht so aus:

# shebang is not needed, this script will effectively be sourced

# Do stuff…
myProgram input "$input"
# Do more stuff…

Die Dateien myProgramInputFile (lokal) und myProgram (Remote) bleibt so wie in Ihrem aktuellen Setup.

Lokale Verwendung:

./myLocalScript <username>@<hostname> myRemoteScript myProgramInputFile

Technische Hinweise und Erklärungen:

  • Im Schritt 2 mktemp erstellt eine Datei in einem temporären Verzeichnis auf dem Remote-Computer. Wir wollen nicht verwenden mktemp -u Um die Situation zu vermeiden, wenn jemand anderes tatsächlich eine Datei mit dem gleichen Namen zwischen uns erstellt Schritt 2 und Schritt 3 .
  • Im Schritt 3 wir könnten verwenden scp wenn wir verwendet haben mktemp -u. Die temporäre Remote-Datei ist bereits vorhanden, so dass wir sie verwenden cat zu schreiben
  • Im Schritt 4 myRemoteScript muss den Pfad zur temporären Datei im Kontext der Remote-Maschine kennen. Deshalb passieren wir unser Lokal $remote_input wie input Variable zur Fernbedienung bash. Auf diese Weise wenn myRemoteScript wird dem besagten zugeführt bash, das $input Darin wird der temporäre Dateipfad angezeigt.
  • Wenn wir die Fernbedienung brechen bash (sagen wir mit single Ctrl + c ) dann myLocalScript wird weitergehen Schritt 5 und mache die Reinigung trotzdem. Dies ist der Grund, warum die Reinigung nicht am Ende ist myRemoteScriptobwohl es sein könnte.


Sohle, einzig, alleinig Methode 1 Ansatz

Dank an Hier Dokumente Sie können einbetten myProgramInputFile in myShellScript.

Das wird einfach sein ob myProgramInputFile ist eine Textdatei und myProgram kann lesen stdin (vielleicht mit myProgram input - Syntax? oder vielleicht wann input wurde weggelassen?)

myShellScript sieht so aus:

# shebang is not needed, this script will effectively be sourced

# Do stuff…

myProgram input - <<"EOF"
The content of myProgramInputFile is pasted here,
it continues here
and here,
and so on.
EOF

# Do more stuff…

Dann werden wir es wie in ausführen Methode 1 :

ssh <username>@<hostname> 'bash -s' < myShellScript

Ob myProgram kann nicht lesen stdin Das Remote-System ermöglicht jedoch die Verwendung /proc/self/ dann sollten wir die entscheidende Zeile einschreiben myShellScript so was:

myProgram input /proc/self/fd/0 <<"EOF"

Ob myProgramInputFile ist mehr als text dann sollten wir es lokal codieren (siehe uuencode. base64 ) und decodieren Sie auf der Gegenseite. Wir sollten auch prüfen, ob es keine gibt EOF Zeile im verschlüsselten Text, ändern Sie hier das Trennzeichen für das Dokument. Beachten Sie, dass base64 verwendet nicht _ so E_O_F ist in diesem Fall absolut sicher (aber vielleicht nicht mit uuencode, Ich weiß es nicht).


Als ein konzeptioneller Beweiß Ich habe das Super User-Favicon gekippt und mit verschlüsselt base64 und in das Skript eingebettet. Ich entschied mich zu demonstrieren /proc/self/fd/0 nähern mit cp aber es könnte sein cat > ~/SUfavicon.ico auch; oder besser gzip -cd > ~/SUfavicon.ico früher in der Pfeife.

Und natürlich würde es in Ihrem Fall geben myProgram anstatt cp.

Beachten Sie in diesem Fall {} sind wichtig, sie machen das Dokument hier gerichtet base64 -d.

# shebang is not needed, this script will effectively be sourced

{ base64 -d | gzip -cd | cp /proc/self/fd/0 ~/SUfavicon.ico ; } <<"E_O_F"
H4sICE3cXFkCA2Zhdmljb24uaWNvAO2XT2jTUBzHf2lnO1HXIAiKYHuSIYhzoCgIlV1EdtDDTmMg
CIKI7DQ9Taq71Il0VfBSmP9QmKziYRd3GCoqu40JIhtiB7sIOm1AcJ1r8/y+5bXEZ1KbtH07uMCH
3/pLvvm8lzYvC5FGAdJ1Qo3R+RaivUQUi1mfx9BPodeOns77ZPXXthZy25IgX2bbZkrz5uIjmvz+
lPKCBZAEmkOeH8/ABOjXt1AXb86NUg+Ov/AtSwOoy6gl1PYq+UtuA0RuHjCw32d+Dn6znrzwH/SZ
fy78w6gBr3lkOpH9DPg53nrNLzykVpzjDp8DatFLfrCXArkHlBLzfwcOgUANed4zE320/es4fRDz
7/Zw/XiP3TxHm5bGK9f/mJ/rv5StfP++8sjmxLU/7DWP7FHkiqhfUNuq5J+AM7h/jvDm/F06geOv
AJ5bBX0uwyvnTV5x/2bE/fsGmQK8U6hdTsGhsMXItI3XNq5hPQlbVPZjtRiKgKi1zvDV5bh9ndH/
9jDG/iCi6yuAVaOcXczuYy78ALPgOtjhND/Za/OzBvjtfARb19HP6a3Dr5GHDS4NvJL8g3795GOD
77bkv6rYn97w/9f+Ecl/Q7G/X/K/B0GF/t1gRRpDBoRU+MUYLjusgznR39lsvxjDAFh2GMdPFX4x
hrNOzwQF178NPHNwl8BEk39//Bk06eC9BfY06veH/Z1gFNwHKRAW/pMO8+5p9P2H/Wnp+A7hT0ru
qWasP1X88vqbbpL/FJgBs+AF0FX6PTx/Nvzr6x9W7B+T/BdV+fm7BshL/g6F/ozknq7z/Uur0bsL
PJbcv8ABRe9/Jekz///ntNt4m/z+N+M27xr8qz79n8A90M2fv//6vso+I0QJEF8jYcQNVnAjCiIG
KwYNZgIWtP4uhA2zNQriFRzz/NwwJF5yHzNCGgiy3wHSerE2FQAA
E_O_F

Führen Sie es wie zuvor aus:

ssh <username>@<hostname> 'bash -s' < myShellScript

Dann wirst du finden ~/SUfavicon.ico auf dem entfernten Rechner.

Kamil Maciorowski
quelle
Vielen Dank für einen solch gründlich und klar erklärten Vorschlag! Ich werde es heute morgen genauer anschauen.
Dave