how to input into stdin from outside process
intro⌗
Recently, my script for evaluating Lisp code in acme started to fail. Basically, I use a program that comes bundled with acme called win which maps acme’s windows into standard input and output.
the previous script⌗
The previous script found what was selected in the current acme window, copied it to the clipboard and executed a command called Send
on the win
window. This was a fine approach.
It failed on one condition; if the selection was higher than 4096 clipboard. After much debugging, I realized that for this to be fixed, I had to go through the acme
source code, win
source code and the plan9port
source code.
I figured that would take too much time and I created a new approach.
inputting into standard input from an outside process⌗
The naive approach would be to find the process’s ID, input your data into /proc/$PID/fd/0
and voila. Unfortunately, that simply inputs the data into the standard input but the underlying process does not reflect that.
The reason as far as I know is due to a syscall that most programs use in-order to check if there was any input by the terminal. Long story short, inputing into standard input simply add the data to the process window but does not let the process see the data as inputted.
xdotool⌗
I chose to not use xdotool because I figured it is inelegant. xdotool basically inputs the string character by character as if the user inputted it from their keyboard.
the better way: FIFO for the win⌗
The idea is simple:
- Create a FIFO
- Create a background process and change its standard input to said FIFO
- Read indefinitely from your standard input and pipe that input into said FIFO
- Write to your FIFO
practical implementation⌗
#!/bin/sh
fifofile="/tmp/fifofile"
mkfifo "$fifofile"
cat < "$fifofile" &
cat /dev/stdin > "$fifofile"
From the outside, do this in-order to input into standard input from the outside:
echo 'Hello World' > /tmp/fifofile
combined with acme⌗
#!/bin/sh
file="$1"
out="$(9p read acme/$winid/rdsel)"
echo "$out" > "$file"
The script above is supposed to be executed within a file window. It has one argument, the path to the FIFO file. It reads the selected text in that file window and pipes it into that file.
Do note: The input is not shown in the terminal.