teoML
teoML

Reputation: 836

Making Python script running in a shell terminal read stdin from another shell instance

I have a python script which reads and input when provided and does something with the input (see process_input below):

import sys

def process_input(input_data):
   # logic to process the input data
   print(f"Processed input: {input_data}")
   return 1  # Return 1 to increment the counter

if __name__ == "__main__":
   input_count = 0
   while True:
       try:
           input_data = sys.stdin.readline().strip()
           if input_data == "exit":
               break
           input_count += process_input(input_data)
           print(f"Input count: {input_count}")
       except (KeyboardInterrupt, EOFError):
           break

Now I want to be able to pass the input to this python script (which I will execute in the terminal) from another shell script (bash).

How can I achieve this?

I tried the following so far:

1.I started the python program
2. I found the PID using ps -xv command
3. I tried redirecting a simple echo input from another terminal using:

echo "some text" > /proc/41267/fd/0 where 41267 was the PID

The result of these actions was that the terminal where the python program is running prints the echo text, but it does not execute the process_input function. I read this related post https://unix.stackexchange.com/questions/385771/writing-to-stdin-of-a-process and as far as I understood the problem is that I am redirecting the stdin to a pseudo-terminal.

In one of the comments it was mentioned to use mkfifo , but I can't understand how to actually use this with my script. What would be the correct way to implement this?

Upvotes: 0

Views: 54

Answers (1)

VPfB
VPfB

Reputation: 17342

/proc/41267/fd/0 is a terminal device. When you read from it (in script1), you read from the terminal. When you write to it (in script2), you write to the terminal. Not what you want.


To connect two scripts the desired way, you need something with "two ends". One of:

  • a pipe - it requires that you start both scripts from one parent process, because the descriptors are inherited.
  • a socketpair - similar to a pipe, but a pipe is unidirectional and a socketpair is bidirectional
  • a named pipe (a.k.a. FIFO), like a pipe, but each script can open it independently
  • a pseudoterminal - it's an overkill, you don't need a controlling terminal functions, process groups, sessions, etc., do you?
  • a Unix domain socket - it's like a local TCP
  • a TCP connection, can communicate across a LAN or even the Internet

Here's a simple demo. Create the FIFO special file with mkfifo /tmp/example-fifo (shell command) or with os.mkfifo(...) in Python. Remove the FIFO when you are finished. In real world you should also make the FIFO not accessible to other users.

FIFO = '/tmp/example-fifo'

with open(FIFO) as inp:
    while line := inp.readline():
        print(f"got: {line.rstrip()}")

and the writer:

FIFO = '/tmp/example-fifo'

TEXT = """\
hello world
line #2
good bye cruel world, I'm leaving you today
"""

with open(FIFO, "w") as outp:
    outp.write(TEXT) 

Upvotes: 1

Related Questions