Python subprocess swaps freezes

I have the following python code that hangs:

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) 

It is supposed to save the line (in_string) to the remote file via ssh.

The file was saved correctly, but then the process freezes. If i use

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

the process does not hang, so I'm sure I misunderstand that the error message is due to the fact that the process exited it.

Do you know how I should write a command so that the "cat" file does not make communication hang?

+6
source share
2 answers

-tt option allocates tty, which prevents the child process from exiting when .communicate() closed by p.stdin ( EOF ignored). It works:

 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) 

You can use paramiko - a clean Python ssh library to write data to a remote file via 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) 

where makedirs_exists_ok() is the mimics os.makedirs() function:

 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) 
+1
source

It makes sense that the cat freezes. He is waiting for EOF . I tried sending EOF to a string, but could not get it to work. Having studied this question, I found a great module for optimizing the use of SSH for command line tasks such as your cat example. This may not be exactly what you need for your use, but it does what your question asks.

Install fabric with

 pip install fabric 

Inside a file called fabfile.py put

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

And then run this from the command line with

 fab -H username@host write_file:in_string=test,path=/path/to/file 
0
source

Source: https://habr.com/ru/post/958976/


All Articles