Ausführen einer lokalen Shell-Funktion auf einem Remote-Host über ssh mit Python

Meine .profile definiert eine Funktion

 myps () { ps -aef|egrep "a|b"|egrep -v "c\-" } 

Ich möchte es von meinem Python-Skript ausführen

 import subprocess subprocess.call("ssh user@box \"$(typeset -f); myps\"", shell=True) 

Einen Fehler zurückholen

 bash: -c: line 0: syntax error near unexpected token `;' bash: -c: line 0: `; myps' 

Entkommen; Ergebnisse in

 bash: ;: command not found 

    3 Solutions collect form web for “Ausführen einer lokalen Shell-Funktion auf einem Remote-Host über ssh mit Python”

    Der ursprüngliche Befehl wurde nicht interpretiert ; Vor myps richtig Mit sh -c fixes das, aber … (siehe Charles Duffy Kommentare unten).

    Mit einer Kombination von Single / Double-Anführungszeichen macht die Syntax manchmal einfacher zu lesen und weniger anfällig für Fehler. In diesem Sinne eine sichere Art, den Befehl auszuführen (vorausgesetzt, die Funktionen in .profile sind tatsächlich in der Shell zugänglich, die vom Subprocess.Popen-Objekt gestartet wurde):

     subprocess.call('ssh user@box "$(typeset -f); myps"', shell=True), 

    Eine alternative (weniger sichere) Methode wäre, sh -c für den Befehl subshell zu verwenden:

     subprocess.call('ssh user@box "sh -c $(echo typeset -f); myps"', shell=True) # myps is treated as a command 

    Dies scheinbar das gleiche Ergebnis:

     subprocess.call('ssh user@box "sh -c typeset -f; myps"', shell=True) 

    Es gibt definitiv alternative Methoden für die Erfüllung dieser Art von Aufgaben, aber dies könnte Ihnen eine Vorstellung davon, was das Problem war mit dem ursprünglichen Befehl.

     script=''' . ~/.profile # load local function definitions so typeset -f can emit them ssh user@box ksh -s <<EOF $(typeset -f) myps EOF ''' import subprocess subprocess.call(['ksh', '-c', script]) # no shell=True 

    Hier sind ein paar relevante Artikel:

    • Die Dotfile, die diese Funktion definiert, muss lokal aufgerufen werden, bevor Sie den typeset -f , um die Definition der Funktion über den Draht zu typeset -f . Standardmäßig führt eine nicht interaktive Shell nicht die Mehrheit der dotfiles aus (je nachdem die ENV Umgebungsvariable eine Ausnahme ist).

      Im gegebenen Beispiel wird dies von der . ~/profile . ~/profile Befehl innerhalb des Skripts.

    • Die Shell muss eine unterstützende typeset , also muss es bash oder ksh , nicht sh (wie von script=True standardmäßig verwendet), die durch ash oder dash bereitgestellt werden kann, fehlt diese Funktion.

      In dem gegebenen Beispiel wird dies durch das Übergeben von ['ksh', '-c'] ist die ersten beiden Argumente für das Argv-Array.

    • typeset muss lokal ausgeführt werden, also kann es nicht in einer argv Position anders als die erste mit script=True . (Um ein Beispiel zu geben: subprocess.Popen(['''printf '%s\n' "$@"''', 'This is just literal data!', '$(touch /tmp/this-is-not-executed)'], shell=True) wertet nur printf '%s\n' "$@" als Shell-Skript aus, This is just literal data! und $(touch /tmp/this-is-not-executed) Als wörtliche Daten übergeben, so dass keine Datei namens /tmp/this-is-not-executed erstellt wird).

      Im gegebenen Beispiel wird dies durch nicht mit script=True geboten.

    • Der explizite Aufruf von ksh -s (oder bash -s , bash -s zutreffend) sorgt dafür, dass die Shell, die Ihre Funktionsdefinitionen auswertet, mit der Shell übereinstimmt, die Sie diese Funktionen geschrieben haben, anstatt sie an sh -c , wie es sonst passieren würde.

      Im angegebenen Beispiel wird dies von ssh user@box ksh -s innerhalb des Skripts bedient.

    Ich habe damit gearbeitet.

     import subprocess import sys import re HOST = "user@" + box COMMAND = 'my long command with many many flags in single quotes' ssh = subprocess.Popen(["ssh", "%s" % HOST, COMMAND], shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) result = ssh.stdout.readlines() 
    Python ist die beste Programmiersprache der Welt.