Search code examples
pythonsubprocessstdinminecraftgnome-terminal

How to write to an other terminal with a running program in it in Python 2.7?


I am currently making a program in python to open minecraft servers. I've already done a window where you can choose a server in a list and launch it or make a backup. When you launch it, a new terminal open (with os.system('gnome-terminal...')) and the java program starts. Is there a way to send some text (like commands) to this java program from the first terminal ?

Here is my code

I've tried many things with subprocess but without a satisfying result.

EDIT:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import gtk
import re
import os
import time

active_button = 0

servers = [["Server 1","/home/myname/Desktop/server1","server.jar"],
            ["Serveur 2","/home/myname/Desktop/server2","server.jar"]]

def button_selection(button, num):
    global active_button
    state=button.state
    if state >= 1:
        active_button = int(num)

def validation(widget):
    path = servers[active_button][1]
    server = servers[active_button][2]
    command = """gnome-terminal --working-directory="%s" -e 'java -jar %s'""" % (path, server)
    print(command)
    os.system(command)

def save(widget):
    path = servers[active_button][1]
    server = servers[active_button][2]
    print "cp -a '%s' /home/myname/Documents/backups_minecraft_servers/%s" % (path+"/world", time.strftime("%d_%m_%Y-%T"))
    os.system("cp -a '%s' /home/myname/Documents/backups_minecraft_servers/%s" % (path+"/world", time.strftime("%d_%m_%Y-%T")))
    print("Backup finished")

def main():
    window = gtk.Window()
    vbox = gtk.VBox()
    hbox = gtk.HBox()

    validate = gtk.Button("Validate")
    validate.connect("clicked", validation)

    backup = gtk.Button("Backup")
    backup.connect("clicked", save)

    hbox.pack_start(validate)
    hbox.pack_start(vbox)
    hbox.pack_start(backup)

    buttons = [gtk.RadioButton(None, servers[0][0])]
    vbox.pack_start(buttons[0])

    for server in servers[1:]:
        buttons.append(gtk.RadioButton(buttons[0], server[0]))
        vbox.pack_start(buttons[-1])

    for i in range(len(buttons)):
        buttons[i].connect("toggled", button_selection, i)


    window.add(hbox)
    window.show_all()
    gtk.main()

if __name__=="__main__":
    main()

Solution

  • First off, don't ever use os.system. Always use the subprocess module for launching new processes, as it handles many of the edge cases much better. subprocess.check_call can do everything os.system can do, and much more, and it checks for errors, something os.system doesn't do.

    Secondly, don't use gnome-terminal to create an interactive terminal to run your subprocess in! Create a pseudoterminal (pty) instead; that way your program can maintain control over the behavior of the child. Underneath the hood, that's how a program like gnome-terminal works itself: it creates a pty for the shell and the programs launched by the shell to run in, and then it reads from the pty and renders the results graphically.

    Your program can create a pty for each child program you want to run, and then your program can communicate with the child program exactly like how gnome-terminal can. You can do this with the pty module in the Python standard library, but you might want to consider using the pexpect package instead as it simplifies the process substantially.

    If you don't need a full terminal, you can do this even more simply by just opening a pipe to the child process. The subprocess module in the standard library provides the Popen class which can be used to do this.

    In your specific case I would recommend pexpect. It's easy to use and will "do the right thing" for this kind of job.