1

Motivation:

I want to run external command (which uses lot of fancy terminal commands) from my program using pseudo terminal and regain control immediately after the external command ends.

Problem:

It works fine, but after the command exits, it hangs until I press additional key (enter, escape, space - all works).

Minimal working example:

This is minimal (or as minimal as I was able to make it) working example of my problem using ls | less as the external program (in "the real" code it uses something else):

import os, pty, termios, sys, select, tty
from subprocess import Popen

original_tty_settings = termios.tcgetattr(sys.stdin)
tty.setraw(sys.stdin.fileno())
try:
        master_fd, slave_fd = pty.openpty()
        p = Popen(
            'ls | less',
            preexec_fn          = os.setsid,
            stdin               = slave_fd,
            stdout              = slave_fd,
            stderr              = slave_fd,
            universal_newlines  = True,
            shell               = True,
        )
        while p.poll() is None:
            r, w, e = select.select([sys.stdin, master_fd], [], [])
            if sys.stdin in r:
                data_in = os.read(sys.stdin.fileno(), 1024)
                os.write(master_fd, data_in)
            elif master_fd in r:
                data_out = os.read(master_fd, 1024)
                if data_out:
                    os.write(sys.stdout.fileno(), data_out)
finally:
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, original_tty_settings)
print('Resuming')

What I expect to happen:

I expect the program runs ls | less, I scroll, I press q, the ls ends and my program prints "Resuming" and ends

What happens instead:

I run the program, it runs ls | less, I scroll, I press q and nothing happens until additional keypress, then it prints "Resuming" and ends.

What I tried:

  • adding all file descriptors to select's xlist (wait for an “exceptional condition”)
  • adding close_fds=True to Popen
  • I feel the main problem is blocking os.read() call, but I was unable to make it non-blocking

Question:

How can I remove the need for additional keypress, after the external program ends?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.