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:
kill -CONT $pid! Tryps --tty $(tty)!! There seem to be conflict about using current PTY!SIGTTOU.