2013-11-28 9 views
6

Ich habe folgende Python-Code, hängt:Python subprocess kommunizieren friert

cmd = ["ssh", "-tt", "-vvv"] + self.common_args 
cmd += [self.host] 
cmd += ["cat > %s" % (out_path)] 
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, 
         stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stdout, stderr = p.communicate(in_string) 

Es soll eine Zeichenfolge (in_string) in eine Remote-Datei über ssh speichern.

Die Datei wird korrekt gespeichert, aber dann hängt der Prozess. Wenn ich

cmd += ["echo"] instead of 
cmd += ["cat > %s" % (out_path)] 

der Prozess hänge nicht so verwenden, bin ich ziemlich sicher, dass ich etwas über die Art und Weise falsch verstanden kommunizieren Auffassung, dass der Prozess beendet wird.

Weißt du, wie ich den Befehl schreiben sollte, damit die "cat> Datei" Kommunikation nicht hängen lässt?

+1

Ich denke, dass [Post] (http://stackoverflow.com/a/19202567/1982962) kann helfen, es ist ein Beispiel dafür, wie man in eine Remote-Datei mit SSH –

+0

Slight Tangens schreiben , aber anstatt einen SSH-Prozess dafür zu verwenden, haben Sie etwas wie [SSHFS] (http://fuse.sourceforge.net/sshfs.html) in Betracht gezogen? Das würde bedeuten, dass Sie sich nur um das Schreiben in eine Datei kümmern müssen, anstatt all diese –

Antwort

1

-tt Option ordnet tty Das verhindert, dass der untergeordnete Prozess beendet wird, wenn .communicate() schließt (EOF wird ignoriert). Dies funktioniert:

import pipes 
from subprocess import Popen, PIPE 

cmd = ["ssh", self.host, "cat > " + pipes.quote(out_path)] # no '-tt' 
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE) 
stdout, stderr = p.communicate(in_string) 

Sie paramiko verwenden könnte - pure Python SSH-Bibliothek, Daten an eine Remote-Datei über ssh zu schreiben:

#!/usr/bin/env python 
import os 
import posixpath 
import sys 
from contextlib import closing 

from paramiko import SSHConfig, SSHClient 

hostname, out_path, in_string = sys.argv[1:] # get from command-line 

# load parameters to setup ssh connection 
config = SSHConfig() 
with open(os.path.expanduser('~/.ssh/config')) as config_file: 
    config.parse(config_file) 
d = config.lookup(hostname) 

# connect 
with closing(SSHClient()) as ssh: 
    ssh.load_system_host_keys() 
    ssh.connect(d['hostname'], username=d.get('user')) 
    with closing(ssh.open_sftp()) as sftp: 
     makedirs_exists_ok(sftp, posixpath.dirname(out_path)) 
     with sftp.open(out_path, 'wb') as remote_file: 
      remote_file.write(in_string) 

wo makedirs_exists_ok() Funktion ahmt os.makedirs():

from functools import partial 
from stat import S_ISDIR 

def isdir(ftp, path): 
    try: 
     return S_ISDIR(ftp.stat(path).st_mode) 
    except EnvironmentError: 
     return None 

def makedirs_exists_ok(ftp, path): 
    def exists_ok(mkdir, name): 
     """Don't raise an error if name is already a directory.""" 
     try: 
      mkdir(name) 
     except EnvironmentError: 
      if not isdir(ftp, name): 
       raise 

    # from os.makedirs() 
    head, tail = posixpath.split(path) 
    if not tail: 
     assert path.endswith(posixpath.sep) 
     head, tail = posixpath.split(head) 

    if head and tail and not isdir(ftp, head): 
     exists_ok(partial(makedirs_exists_ok, ftp), head) # recursive call 

    # do create directory 
    assert isdir(ftp, head) 
    exists_ok(ftp.mkdir, path) 
+0

aber warum funktioniert es mit -tt + echo? Ihre Erklärung scheint zu implizieren, dass es auch nicht mit echo funktionieren sollte!? –

+0

@JeromeWAGNER: 'echo' erwartet keine Eingabe auf stdin. Probieren Sie ein Programm aus, das nicht beendet wird, bis alle Eingaben (Stdin) verbraucht sind.Obwohl ich es auch nicht vollständig verstehe. Es könnte ein Fehler irgendwo in der Kette mit dem Schließen von Pseudo-tty Dateideskriptoren sein. Es ist plattformabhängig zB hier ist [Code, der 'pty' verwendet (so stelle ich mir vor, dass ssh Remote Child Prozesse startet (ich kann mich komplett irren))] (http://stackoverflow.com/a/12471855/4279) – jfs

0

Es macht Sinn, dass der cat Befehl hängt. Es wartet auf eine EOF. Ich habe versucht, eine EOF in der Zeichenfolge zu senden, konnte es aber nicht zum Funktionieren bringen. Bei der Untersuchung dieser Frage habe ich ein großartiges Modul gefunden, um die Verwendung von SSH für Kommandozeilenaufgaben wie das Beispiel Ihrer Katze zu rationalisieren. Es ist möglicherweise nicht genau das, was Sie für Ihren Anwendungsfall benötigen, aber es erfüllt Ihre Fragen.

Installieren fabric mit

pip install fabric 

Innerhalb einer Datei

from fabric.api import run 

def write_file(in_string, path): 
    run('echo {} > {}'.format(in_string,path)) 

fabfile.py setzen genannt und diese dann mit der Eingabeaufforderung ausführen,

fab -H [email protected] write_file:in_string=test,path=/path/to/file 
+0

Dank für die Idee, aber ich versuche, ein vorhandenes Projekt (ansible) zu patchen und die Abhängigkeit von Fabric würde nicht akzeptiert werden. –

+0

willkommen. aber ja, ich dachte mir, dass es nicht für Ihre Bedürfnisse geeignet sein könnte. Hat die Antwort von Kobi K für Sie funktioniert? –

+0

ja Kobi K's Antwort scheint zu funktionieren, aber ich verstehe das Problem mit der Kommunikation nicht. Ich fand, dass das Entfernen des "-tt" das Ding zum Funktionieren bringt; Das ist ein Geheimnis für mich. –

Verwandte Themen