1

I am trying to write a script to initiate a daemon which while pipe its output and input via two named pipes $FIFO.out and $FIFO.in respectively. What I wish to do is to give the client process the ability to talk with the daemon whenever it wants by using the named pipes.

Here is what I have already implemented: (The daemon is a qalc process)

#!/bin/sh
# Daemon script

FIFO="/tmp/qcalc"
mkfifo "$FIFO.out" "$FIFO.in"
exec qalc -t -u8 <"$FIFO.in" >"$FIFO.out"
#!/bin/sh
# Client script

FIFO="/tmp/qcalc"

talk() {
    echo "$1" >"$FIFO.in"

    # I'm not interested in the first two lines
    read -r _ <"$FIFO.out"
    read -r _ <"$FIFO.out"

    read -r result <"$FIFO.out"
    echo "$result"
}

talk 1
talk 2

The problem with this implementation is that I can only talk to the daemon once, and after that the client just freezes at the blocking read. Here is how it looks in the shell:

$ ./daemon &
[2] 57848
$ ./client
1
[2]  + done       ./daemon
^C./client: 13: cannot open /tmp/qcalc.out: Interrupted system call
Utkarsh Verma
  • 190
  • 2
  • 15
  • Check `socat PIPE/tmp/qcalc SYSTEM:qcalc....` to manage your service. – KamilCuk Mar 25 '23 at 06:01
  • Under [tag:bash], you could use `coproc` instead of named pipe! Have a look at [this answer](https://stackoverflow.com/a/41236640/1765658), how I use `bc` in same maner you try to use `qalc`. At end, you will find my `shell-connector` for playing with a lot of *backgrounded tools*, like `bc`, `date`, `mysql`, and others – F. Hauri - Give Up GitHub Mar 25 '23 at 12:46

1 Answers1

0

This was a nice edge case when using named pipes and I learned a lot trying to get this system to work:

Firstly, here's the final implementation I wrote:

#!/bin/sh
# Daemon script

FIFO="/tmp/qcalc"
mkfifo "$FIFO.in" "$FIFO.out"

qalc -t -u8 <"$FIFO.in" >"$FIFO.out" &
qalcPID="$!"
exec 3>"$FIFO.in" # Dummy writer to keep the pipe alive
wait "$qalcPID"
exec 3>&-
#!/bin/sh
# Client script

FIFO="/tmp/qcalc"

echo "$1" >"$FIFO.in"

exec 3<"$FIFO.out"
read -r _ <&3
read -r _ <&3
read -r result <&3
read -r _ <&3
echo "$result"
exec 3<&-

What I understood from another SE question about pipes was that reading end pipe will get an EOF or it will be closed if the writing end is not connected.

As @PCDSandwichMan correctly pointed out in his answer, my previous attempt failed because qalc was closing when it detected $FIFO.in closing. Therefore, to keep the pipe alive, I added a dummy writer after qalc is launched.

qalc -t -u8 <"$FIFO.in" >"$FIFO.out" &
exec 3>"$FIFO.in" # Dummy writer to keep the pipe alive

The writer has to be added after a reader for the pipe is established so I launch qalc as a background process and then do it.

Utkarsh Verma
  • 190
  • 2
  • 15