0

Which is the best way of redirect the output of a command to a VTE terminal?

i came with this idea:

On the VTE execute:

tty > /usr/tmp/terminal_number    

then read the file from the python program:

with open('/usr/tmp/terminal_number', 'r') as f:
    self.VTE_redirect_path=f.readline()

then execute the bash commands, for exemple:

os.system('''echo "foo" >  {0}'''.format(self.VTE_redirect_path))

The problem of this method is that the file terminal_number containing /dev/pts/# needs to be refreshed. Also i don't really like the idea of having to create files to communicate. Is there any direct solution?

  • @Quentin Engles Question related to [this thread](https://stackoverflow.com/questions/11804455/how-to-send-commands-to-pygobject-virtual-terminal/11810239?noredirect=1#comment39311005_11810239) –  Aug 11 '14 at 02:27

2 Answers2

2

@Quentin The solution that you gave me prints the console output really bad (it doesn't indents) so i had to use my solution. Here is a clear example:

from gi.repository import Gtk, GObject, Vte, GLib
import os, time, threading

def command_on_VTE(self,command):
    length=len(command)
    self.terminal.feed_child(command, length)


class TheWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="inherited cell renderer")
        self.set_default_size(600, 300)
        self.terminal=Vte.Terminal()
        self.terminal.fork_command_full(
                Vte.PtyFlags.DEFAULT, #default is fine
                os.environ['HOME'], #where to start the command?
                ["/bin/bash"], #where is the emulator?
                [], #it's ok to leave this list empty
                GLib.SpawnFlags.DO_NOT_REAP_CHILD,
                None, #at least None is required
                None,
                )

        #set up the interface
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        #a scroll window is required for the terminal
        scroller = Gtk.ScrolledWindow()
        scroller.set_hexpand(True)
        scroller.set_vexpand(True)
        scroller.add(self.terminal)
        box.pack_start(scroller, False, True, 2)
        self.add(box)

        #To get the command to automatically run
        #a newline(\n) character is used at the end of the
        #command string.
        command_on_VTE(self,'''tty > /tmp/terminal_number\n''') # Get the terminal ID

        # read the terminal ID
        while not os.path.exists("/tmp/terminal_number"):
            time.sleep(0.1) 
        with open('/tmp/terminal_number', 'r') as f:
            self.VTE_redirect_path=f.readline()
            os.remove('/tmp/terminal_number')

        # this cleans the vte
        os.system('''printf "\\033c" > {0}'''.format(self.VTE_redirect_path)) 


        # this calls the exemple
        threading.Thread(target=self.make_a_test).start()   

    def make_a_test(self):
        os.system('''ls -laR /home/ > {rdc}
echo "-------- The listing ended -------

Note that the input of the commands are not printed
" > {rdc}'''.format(rdc=self.VTE_redirect_path))

win = TheWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

I haven't found a way of getting the Terminal ID with out passing for the creation of a temporary file. This could be skipped if there is some way to pass a variable from the VTE to the python script. Any help on this would be great!

  • You could try self.terminal.connect_after('commit', function) to get the input. Sorry about taking so long. – Quentin Engles Nov 03 '14 at 00:59
  • 1
    I just found that if the point is to hide the "input " of the commands, this can be disabled by using `stty -echo`, so actually when sending commands to the terminal they won't be printed! –  Jan 25 '15 at 17:07
  • @QuentinEngles is this `commit` only stdout? If yes, how get the stderr as well? – Matthias Jan 14 '20 at 17:20
0

In VTE you use terminal.feed("string")

See vte_terminal_feed.

With python Popen is the suggested method to execute commands. If you are wanting to use commands then you should do this.

#Uncomment the next line to get the print() function of python 3
#from __future__ import print_function
import os
import subprocess
from subprocess import Popen
command = "echo \"something\""
env = os.environ.copy()
try:
    po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
        universal_newlines=True, env=env)
    po.wait()
    output, error_output = po.communicate()

    if po.returncode:
        print(error_output)
    else:
        print(output)

except OSError as e:
    print('Execution failed:', e, file=sys.stderr)

If you want to use gtk with gtk vte then do this instead.

#place the following in a method of a vte instance
env = os.environ.copy()
try:
    po = Popen(command, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE,
        universal_newlines=True, env=env)
    po.wait()
    output, error_output = po.communicate()

    if po.returncode:
        print(error_output)
    else:
        self.feed(output) #here you're printing to your terminal.

except OSError as e:
    print('Execution failed:', e, file=sys.stderr)

For the finest control in a regular terminal you can try the cmd module. This will require that you produce your own prompt so it is a more specific option to get what you want.

Quentin Engles
  • 2,744
  • 1
  • 20
  • 33
  • I'm trying to do the VTE printing, i just the following error `print('Execution failed:', e, file=sys.stderr) ^ SyntaxError: invalid syntax` –  Aug 11 '14 at 03:00
  • print() is python 3. You probably need to either install python 3, or take the parenthesis off of print. – Quentin Engles Aug 11 '14 at 03:43
  • @rsm I don't have enough rep to accept your edit so I did it manually. – Quentin Engles Aug 11 '14 at 03:48
  • The solutions "works" but only when i send commands from the main process of the program. If i send commands from sub-process or threads i get the printing in the terminal not in the VTE. Is there any solution to this? –  Aug 11 '14 at 13:08
  • You have to feed it to the vte terminal, or start the commands in the vte terminal. – Quentin Engles Aug 11 '14 at 20:09
  • The problem was that i was trying to send the command from a child process of the GUI. I replaced the child process by a thread and it worked :) –  Aug 11 '14 at 22:24
  • Maybe you should also provide an answer too if you were having specialized problems. Two acceptable answers are not a problem. – Quentin Engles Aug 11 '14 at 23:02