2013-11-28 3 views
6

У меня есть следующий код питона, который висит:питон подпроцесс общаться замерзает

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) 

Предполагается сохранить строку (in_string) в удаленный файл через SSH.

Файл сохранен правильно, но затем процесс зависает. Если я использую

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

процесс не висит, так что я уверен, что я неправильно что-то о том, как общаться считает, что процесс завершился.

Знаете ли вы, как я должен написать команду, чтобы файл «cat» не делал связь зависающей?

+1

Я думаю, что это [сообщение] (http://stackoverflow.com/a/19202567/1982962) может помочь, это пример того, как писать в удаленный файл с помощью SSH –

+0

Плавный касательный , но вместо того, чтобы использовать SSH-процесс для этого, рассмотрели ли вы что-то вроде [SSHFS] (http://fuse.sourceforge.net/sshfs.html)? Это означало бы, что вам нужно будет только беспокоиться о записи в файл, вместо того, чтобы поддерживать все это –

ответ

1

-tt вариант выделяет TTY который предотвращает выход дочернего процесса, когда .communicate() закрывается p.stdin (EOF игнорируется). Это работает:

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) 

Вы можете использовать paramiko - чистая библиотека Python SSH, для записи данных в удаленный файл через SSH:

#!/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) 

где makedirs_exists_ok() функция подражает 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

, но почему он работает с -tt + echo? ваше объяснение, по-видимому, подразумевает, что он не должен работать с эхом !? –

+0

@JeromeWAGNER: 'echo' не ожидает ввода на stdin. Попробуйте любую программу, которая не выйдет до тех пор, пока не будет использован весь вход (stdin).Хотя я тоже не понимаю этого. Это может быть ошибка где-то в цепочке с закрытием дескрипторов файлов псевдо-tty. Это зависит от платформы, например, здесь [код, который использует 'pty' (как я себе представляю, ssh запускает дочерние дочерние процессы (я могу быть абсолютно ошибаюсь в этом))] (http://stackoverflow.com/a/12471855/4279) – jfs

0

Имеет смысл, что команда cat висит. Он ждет EOF. Я попытался отправить EOF в строку, но не смог заставить ее работать. Изучив этот вопрос, я нашел отличный модуль для оптимизации использования SSH для задач командной строки, таких как пример вашей кошки. Возможно, это не совсем то, что вам нужно для вашего использования, но оно делает то, о чем спрашивает ваш вопрос.

Установка fabric с

pip install fabric 

Внутри файла с именем fabfile.py поставил

from fabric.api import run 

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

А затем запустить из командной строки с,

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

благодаря этой идее, но я пытаюсь исправить существующий проект (возможно), и зависимость от ткани не будет принята. –

+0

добро пожаловать. но да, я полагал, что это не подходит для ваших нужд. Ответ Kobi K работал на вас? –

+0

да Ответ Kobi K, похоже, работает, но я не понимаю проблему с общением. Я обнаружил, что удаление «-tt» заставляет работать; это для меня мистерия. –

Смежные вопросы