0

In (Debian) Linux I'd like to start an interactive Bash session and then pass it commands.

With my attempt it seems Bash isn't behaving as it would in a real terminal and abruptly stops during initialization.

I’d like to understand this behavior and how to fix it. It's important to interact with an interactive Bash session so I can pass it commands as if I were typing them directly. This is practical when commands change variables that are then used by others. Beyond that, I also want to improve my understanding and resolve this issue without resorting to an external package.

This is my failing attempt:

# file: Shell.py
import os
import pty
import subprocess
import time


class Shell:
    def __init__(self):
        # Start a persistent interactive Bash session
        self.master, self.slave = pty.openpty()
        self.process = subprocess.Popen(
            ["bash", "-i"], stdin=self.slave, stdout=self.master, stderr=self.master
        )

    def execute(self, command: str) -> str:
        time.sleep(2)  # Wait for the Bash prompt to appear

        # Send command to Bash
        os.write(self.master, (command + "\n").encode())

        # Capture output until the Bash prompt appears
        output = []
        while True:
            data = os.read(self.master, 1024).decode()
            output.append(data)
            if data.endswith("$ ") or data.endswith("# "):
                break
        return "".join(output).strip()

    def close(self):
        # Terminate the Bash process
        self.process.terminate()
        os.close(self.master)
        os.close(self.slave)

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()


# Example usage
with Shell() as shell:
    print(shell.execute("echo Hello, World!"))
    print(shell.execute("export TEST_VAR='Persistent Variable'"))
    print(shell.execute("echo $TEST_VAR"))
    time.sleep(10)  # Wait enough time for the persistent variable to be available

When I run this script I get this weird behavior:

$ python3 Shell.py 

[1]+  Stopped                 python3 Shell.py

I'll prove some more information based on suggestions in the comments. After running the above I continue to run:

$ jobs -l
[1]+ 15437 Stopped (tty input)     python3 Shell.py
$ kill -CONT 15437
$ jobs
[1]+  Running                 python3 Shell.py &
$ ps --tty $(tty)
    PID TTY          TIME CMD
   9103 pts/2    00:00:00 bash
  15437 pts/2    00:00:00 python3
  15438 pts/2    00:00:00 bash
  15501 pts/2    00:00:00 ps

So, it looks like python3 and the bash process it started both use the same TTY as the bash instance used to call python3 Shell.py.

Related but not a solution:

12
  • Process is stopped not killed! His pid still exist, you may (unsuccessfully) try kill -CONT $pid! Try ps --tty $(tty)!! There seem to be conflict about using current PTY! Commented Oct 31, 2024 at 17:51
  • Why isn't Pexpect a solution? This is what it's intended for. Commented Oct 31, 2024 at 18:48
  • You need to put the shell process in its own process group, and make the pty slave its controlling terminal. Otherwise it gets stopped due to SIGTTOU. Commented Oct 31, 2024 at 18:50
  • @Barmar: Because I want to understand how to solve the problem. Commented Oct 31, 2024 at 18:51
  • @F.Hauri-GiveUpGitHub Thanks. I added some more details based on your comment. Commented Oct 31, 2024 at 18:51

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.