'Send STDIN and get STDOUT from a running process

I have a c++ compiled code I can run, let call it run_process.

To describe run_process, it's a code which is waiting continuously (infinite loop/while True) for text input and make text preprocessing then print the preprocessed input in output:

run_process

I would like to know if I can make some command/request to send input/STDIN text to this running process and get the output text, for the moment I would like to avoid to edit run_process and find an "external" solution.

I tried the solution proposed here: https://serverfault.com/a/178470 and run:

echo "test"  > /proc/2657677/fd/0
echo "test\n"  > /proc/2657677/fd/0
echo -ne "test\n"  > /proc/2657677/fd/0

And got this:

enter image description here

I don't get the output, it's like it can not simulate the ENTER key, or even just print the text next to "Input string" because when I press ENTER key I get nothing in output:

enter image description here

If you have any solution for this even using python or any other language, all solution will be interesting.

For more details, the code run_process use c++ readline function:

char* input = readline("Input string: ");

Line 90 from this: https://opengrm.org/doxygen/thrax/html/rewrite-tester-utils_8cc_source.html#l00245 and for more information you can see that the code I called "run_process" is actually in line 247.



Solution 1:[1]

The readline library does way more than just reading a single line of text. I do not know the exact rules of what it does in what circumstances, but it will detect the presence of a terminal and enable things like line editing and command line history if told so.

If you start the program run_process, its stdin and stdout streams are usually connected to the terminal running the shell that is used to start the program. This might either be a real terminal or more likely these days be a pseudo terminal. Such a pseudo terminal has a master side, that is controlled by the terminal emulator you are using (e.g. xterm), and a client side, that is used as stdin and stdout of the foreground process running in that terminal.

If you are writing to the /proc/.../fd/0 file, you are writing to the client side of the pseudo terminal. This bypasses all terminal functionality, that is normally done by the pseudo terminal driver. The data is instead sent to the process as it is written.

The readline library knows that it is connected to a pseudo terminal and uses its functionality to e.g. detect ENTER key presses (this enables multiline "lines" in readline). The essential part here is, that readline does not only rely on the input character stream for line breaking, but also on the (pseudo) terminal features. This is the reason, why directly writing to /proc/.../fd/0 (which bypasses these features) does not work in combination with readline.

Now I think you have several options (there might be more, but these are the ones that came into my mind):

  • Don't use readline, but directly read from stdin and break lines on newline characters. You will lose all the cool features from readline though. If your program is designed to only be used with generated input, this might not be a problem, but if the program should also feature a good interactive input you probably don't want to do without readline.

  • Don't use a pseudo terminal for the input stream. You can instead use for example a fifo special file like this

    $ mkfifo myfifo
    $ tail -f myfifo | ./run_process 
    

    and send data to the process with

    $ echo "test" > myfifo
    

    and finally delete the fifo again using rm myfifo. The tail -f command is used to keep the fifo open between different echos.

  • use a tool like socat for creating an additional pseudo terminal for which you have control on the master side:

    $ tty
    $ socat STDIO,raw,echo=0 SYSTEM:./run_process,pty,stderr
    

    and write to the process by

    $ echo "test" > /dev/pts/<number_returned_by_the_above_tty_command>
    

    With socat you also have a lot of different options. If you change the STDIO source to a different connection option of socat, you can easily make the run_process program for example listen on tcp connections or unix domain sockets, which also can be used for two way data transfer.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Jakob Stark