Führen Sie ein lokales Skript mit lokaler Eingabedatei auf dem Remote-Host aus

Führen Sie ein lokales Skript mit lokaler Eingabedatei auf dem Remote-Host aus

Ich habe ein lokales Skript, das ich auf mehreren Remote-Servern ausführen möchte. Die von mir verwendete Befehlssyntax ist:

ssh <remote_server> "bash -s" < ./local_script.sh

Das funktioniert gut und ich kann sogar Parameter übergeben anlocal_script.sh. Ich würde ihm jedoch wirklich gerne eine Eingabedatei übergeben, wie in:

local_script.sh < local_file.txt

Die Kombination dieser beiden Aussagen ergibt:

ssh <remote_server> "bash -s" < ./local_script.sh < local_file.txt

Wenn ich das ausführe, bekomme ich

bash: line 1: FOO: command not found
bash: line 2: BAR: command not found
bash: line 3: BAZ: command not found
...

wobei FOO, BAR, BAZ usw. das erste Wort in jeder Zeile sindlokale_datei.txt:

FOO     FOO_PARAM1
BAR     BAR_PARAM1
BAZ     BAZ_PARAM2
...

Es sieht also so aus, als ob "bash -s"der Remote-Server interpretiertlokale_datei.txtals Skriptdatei statt als Eingabedatei fürlocal_script.sh. Gibt es eine Möglichkeit, dies zu beheben (außer ein Wrapper-Skript zu erstellen)?

Antwort1

Während sshes zwei separate Ausgabeströme (für stdout und stderr) bereitstellt, speist es nur einen Eingabestrom (stdin). Sie müssen also den Skriptinhalt und die Eingabedatei über unterschiedliche Mechanismen übergeben.

Beispielsweise einmal über eine Variable, einmal über stdin:

LC_CODE=$(cat local_script.sh) ssh host 'eval "$LC_CODE"' < input

(vorausgesetzt, sowohl Ihr sshClient übergibt die LC_*Variable ( SendEnvin ssh_config) als auch der sshdServer akzeptiert sie ( AcceptEnvin sshd_config))

Oder übergeben Sie den Inhalt einfach local_script.shals Remote-Shell-Code, vorausgesetzt, die Login-Shell des Remote-Benutzers ist die richtige für die Syntax dieses Skripts:

ssh host "$(cat local_script.sh)" < input

Oder verketten Sie den Code und die Eingabe, die an sshdie Standardeingabe von gesendet werden, wie folgt:

{
  echo '{'; cat local_script.sh; echo '}; exit'
  cat input
} | ssh host 'bash -s some arguments'

Hier sorgt die Verwendung von „ bashweil“ dafür, dass die Eingabe Byte für Byte gelesen wird, um nicht über diese Zeile hinaus zu lesen, während dies nicht bei allen anderen Shells der Fall ist.bash}; exit

Oder wenn sedsich auf dem Remote-Host GNU befindet sed:

echo '#END-OF-SCRIPT' | cat local_script.sh - input |
  ssh host 'set some arguments; eval "$(sed -u "/^#END-OF-SCRIPT/q")"'

(hier wird der Code von der Login-Shell des Remote-Benutzers ausgewertet und es wird angenommen, dass er Bourne-ähnlich ist)

Antwort2

Hier ist eine elegantere Lösung mit dem BASH-Operator „here-strings“ ('<<<').

ssh -t host "/bin/bash <(base64 --decode <<<'$(base64 < script)' )"

Es nimmt das Skript, konvertiert es in eine Base64-Zeichenfolge, konvertiert es im SSH-Befehl zurück und gibt es als Pipe-Dateinamen an die Bash weiter.

Damit ein Skript eine interaktive Shell einrichten kann, muss dem „Pipe-Dateinamen“ das Präfix „--rcfile“ vorangestellt werden.

ssh -t host "/bin/bash --rcfile <(base64 --decode <<<'$(base64 < script)' )"

Mehr dazu... https://antofthy.gitlab.io/info/apps/ssh_remote_commands.txt

Antwort3

Dies funktioniert gut und ermöglicht Ihnen sogar, den Inhalt mehrerer Dateien an das Skript zu übergeben:

ssh host "bash -s -- '$(cat local_file_1.txt)'  '$(cat local_file_2.txt)'" < local_script.sh

Die Erklärung ist, dass beim Anmelden sshausgeführt wird bash -s, wobei die Skriptargumente alles nach sind --. Daher $1wird der Inhalt von sein local_file_1.txtund $2wird der Inhalt von sein local_file_2.txt. bash -sliest Befehle von stdin, das von kommt < local_script.sh.

verwandte Informationen