Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Python, how to write a string to a file on a remote machine?

On Machine1, I have a Python2.7 script that computes a big (up to 10MB) binary string in RAM that I'd like to write to a disk file on Machine2, which is a remote machine. What is the best way to do this?

Constraints:

  • Both machines are Ubuntu 13.04. The connection between them is fast -- they are on the same network.

  • The destination directory might not yet exist on Machine2, so it might need to be created.

  • If it's easy, I would like to avoid writing the string from RAM to a temporary disk file on Machine1. Does that eliminate solutions that might use a system call to rsync?

  • Because the string is binary, it might contain bytes that could be interpreted as a newline. This would seem to rule out solutions that might use a system call to the echo command on Machine2.

  • I would like this to be as lightweight on Machine2 as possible. Thus, I would like to avoid running services like ftp on Machine2 or engage in other configuration activities there. Plus, I don't understand security that well, and so would like to avoid opening additional ports unless truly necessary.

  • I have ssh keys set up on Machine1 and Machine2, and would like to use them for authentication.

  • EDIT: Machine1 is running multiple threads, and so it is possible that more than one thread could attempt to write to the same file on Machine2 at overlapping times. I do not mind the inefficiency caused by having the file written twice (or more) in this case, but the resulting datafile on Machine2 should not be corrupted by simultaneous writes. Maybe an OS lock on Machine2 is needed?

I'm rooting for an rsync solution, since it is a self-contained entity that I understand reasonably well, and requires no configuration on Machine2.

like image 621
Iron Pillow Avatar asked Oct 05 '13 20:10

Iron Pillow


People also ask

Can you write a string to a file in Python?

To write string to a file in Python, we can call write() function on the text file object and pass the string as argument to this write() function.

How do you send text to a file in Python?

To write to a text file in Python, you follow these steps: First, open the text file for writing (or append) using the open() function. Second, write to the text file using the write() or writelines() method. Third, close the file using the close() method.

How do you write a string of text into a file?

To write string to a Text File, follow these sequence of steps: Open file in write mode using open() function. Write string to the file using write() method. Close the file using close() method.


4 Answers

Paramiko supports opening files on remote machines:

import paramiko

def put_file(machinename, username, dirname, filename, data):
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(machinename, username=username)
    sftp = ssh.open_sftp()
    try:
        sftp.mkdir(dirname)
    except IOError:
        pass
    f = sftp.open(dirname + '/' + filename, 'w')
    f.write(data)
    f.close()
    ssh.close()


data = 'This is arbitrary data\n'.encode('ascii')
put_file('v13', 'rob', '/tmp/dir', 'file.bin', data)
like image 141
Robᵩ Avatar answered Oct 16 '22 23:10

Robᵩ


You open a new SSH process to Machine2 using subprocess.Popen and then you write your data to its STDIN.

import subprocess

cmd = ['ssh', 'user@machine2',
       'mkdir -p output/dir; cat - > output/dir/file.dat']

p = subprocess.Popen(cmd, stdin=subprocess.PIPE)

your_inmem_data = 'foobarbaz\0' * 1024 * 1024

for chunk_ix in range(0, len(your_inmem_data), 1024):
    chunk = your_inmem_data[chunk_ix:chunk_ix + 1024]
    p.stdin.write(chunk)

I've just verified that it works as advertised and copies all of the 10485760 dummy bytes.

P.S. A potentially cleaner/more elegant solution would be to have the Python program write its output to sys.stdout instead and do the piping to ssh externally:

$ python process.py | ssh <the same ssh command>
like image 28
Erik Kaplun Avatar answered Oct 17 '22 01:10

Erik Kaplun


A bit modification to @Erik Kaplun answer, the below code worked for me. (using communicate() rather than .stdin.write)

import subprocess
# convert data to compatible format
cmd = ['ssh', 'user@machine2', 'cat - > /path/filename']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE)
p.communicate(data)
like image 3
Enes R. A. Avatar answered Oct 17 '22 00:10

Enes R. A.


We can write string to remote file in three simple steps:

  1. Write string to a temp file
  2. Copy temp file to remote host
  3. Remove temp file

Here is my code (without any third parties)

import os

content = 'sample text'
remote_host = 'your-remote-host'
remote_file = 'remote_file.txt'

# step 1
tmp_file = 'tmp_file.txt'
open(tmp_file, 'w').write(content)

# step 2
command = 'scp %s %s:%s' % (tmp_file, remote_host, remote_file)
os.system(command)

# step 3
os.remove(tmp_file)
like image 1
Vu Anh Avatar answered Oct 16 '22 23:10

Vu Anh