split stdout and stdin in same terminal

Added 17 Sep 2023, 1:06 p.m. edited 17 Sep 2023, 1:42 p.m.

When using a serial link to communicate with for example an application running on a microcontroller you might find that what you are typing is interrupted by real time feedback from the embedded application.

I've found it useful to communicate using a split screen so that my input and output are separate, yet conveniently in the same terminal.

Just for the purposes of illustration, in place of something on for example a microcontroller, I've created a simple echo application that reads a line from stdin, reverses it and then outputs it on stdout.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main() {
char str[1024] = { 0 };
char* line = str;
size_t len = 1023;

while (1) {
getline(&line, &len, stdin);
if (!strcasecmp(line, "quit\n")) {
char* str = line;
char* end = line + strlen(line) - 2;
while (str < end) {
*str ^= *end; *end ^= *str; *str ^= *end; // EOR swap
str++; end--;
printf("> %s", line);

Compiling this is trivial

gcc test.c -o test

bare in mind although this doesn't interrupt our input, a real world example could be reading the input while continually spewing output...

To make this whole process easier a named pipe is used, this only need be created once

mkfifo fifo

Relying on tail -f has a few issues so a simple python script will feed the output pane and terminate on EOF

#!/usr/bin/env python3
FIFO_PATH = './fifo'
with open(FIFO_PATH, 'r') as lines:
while True:
current = next(lines)
print(current, end='')
except StopIteration:

So now we have nearly all the pieces needed, just finally a little script to kick everything off in a multiplexed terminal


tmux new-session -d ./ \; split-window -p 25 bash -c "stdbuf -i0 -o0 -e0 ./test 2>&1 > ./fifo" \; attach

There's a lot going on in one busy little line, so its worth unpacking!

tmux is used to multiplex the screen, in a new session the reader python script is run - this is the output (that could be coming from a microcontroller for example) its sole job is to display what written to the named pipe.  The screen is split horizontally but the new "half" only gets 25% of the screen (this is output)

This bottom part of the screen is the bit with the misbehaving spew, more likely a minicom command or a serial host application sending commands to a microcontroller (in place of the test executable).  I'm using the stdbuf command here just to ensure that its completely unbuffered, stdout and strerr are redirected from the test application to the named pipe

You could easily extend the script to take a parameter in place of the test application, for example whatever host application you have talking to your microcontroller...

Finally you can see the input on the smaller lower portion and above it the reversed output