-1

I have a problem that I can't seem to solve involving two named pipes. Basically, I have two processes that I don't have control over. They are communicating via named pipes (mknod pipe p). Process one is a GPS driver that outputs messages in NMEA0183 format. Process two is a navigation application that reads NMEA0183 data to get location and date/time from GPS. I need to adjust this data (reason: google for WNRO or ask).

  1. First process is continuously writing data (~5-8 lines of text) in 1 second intervals into /var/run/one.pipe and leaving it there until it is read(?)

  2. Second process is reading this data from the named pipe. I can change the name of the named pipe to read from. I changed it to /var/run/two.pipe

The final goal is to read data from one.pipe, do some processing, and then pass it to two.pipe. However, for the meantime and for testing I am just trying to copy the data one by one from one.pipe to two.pipe. I figured it's not feasible wasting time on the whole processing until I can manage to complete this (simpler?) task.

A very simple shell script works: copy.sh

#!/bin/sh
cat one.pipe > two.pipe &

Now I captured some of the data that the source process writes to one.pipe and tried to manually write it to two.pipe to be read by the reading process:

#!/bin/sh

while true; do
  echo "\$GPGGA,,,,,,,,*12" > two.pipe
  echo "\$GPGSA,,,,,,,,*23" > two.pipe
  echo "\$GPRMC,,,,,,,,*34" > two.pipe
  echo "\$GPGSV,,,,,,,,*45" > two.pipe
  echo "\$GPGSV,,,,,,,,*56" > two.pipe
  echo "\$GPGSV,,,,,,,,*67" > two.pipe
  # checksums (*xx) are just examples here
  sleep 1 > two.pipe
done

Now this doesn't work well. If I compare cat one.pipe vs. cat two.pipe I can see that the messages in two.pipe don't "pile up", while they do from the original process, that writes into one.pipe. E.g., if I start my script, it should write to the named pipe and continue to do so on and on. When I read that pipe with cat it should output all the data so far (assuming the fifo-buffer hasn't been filled yet). It is first-in-first-out afterall, isn't it?!

Also, cat now frequently stops seemingly randomly. And finally, also the process that I can't control which is reading from two.pipe seems to not work well with the data/causes the script to terminate.

I don't even understand why the script terminates, even though it contains an infinite loop?!

What am I overseeing here? If this is not feasible to write in shell, C would also be an option.

2
while true; do
  echo "\$GPGGA,,,,,,,,*12" > two.pipe
  echo "\$GPGSA,,,,,,,,*23" > two.pipe
  ...

Each ... > two.pipe line from your script will open and close the two.pipe fifo, and closing it may cause any read from the other end of the pipe to return end-of-file, and the cat to exit.

I suggest for starting just to open the fifo once for your whole script with exec:

#!/bin/sh

exec > two.pipe

while true; do
  echo "\$GPGGA,,,,,,,,*12"
  echo "\$GPGSA,,,,,,,,*23"
  ...
  sleep 1
done

You can "pin" a fifo by opening both of its ends into the same handle with eg.

exec 7<>two.fifo

As long as the process doing it hasn't exited and hasn't closed the file descriptor 7, that will make sure that the processes reading from it won't get an end-of-file when all the other handles to its writing end are closed, and the processes writing to it won't be killed by a SIGPIPE when all the other handles to its reading end are closed.

Also, opening both ends of a named fifo at the same time won't block.

  • Thx for the explanation. Now I tried that, but still seems to terminate randomly (why even with infinite loop???). And also in this example data doesn't stack. If I start the script and wait a couple of seconds and then do "cat two.pipe" I can see that writing to the pipe stopped at "sleep 1" during the first run of the loop (added a counter to reassure myself). – TJJ May 23 at 0:32
  • If you use the script as in my example, and then do a cat two.pipe, the cat will print, in order everything that the script writes to two.pipe. When you kill the cat, the script script will be killed too by the SIGPIPE signal when trying to write to a pipe with no readers. (Notice that echo is a shell built-in; it's not the echo which will be killed, but the whole script). – mosvy May 23 at 0:41
  • Sometimes it seems "cat" is reading to fast...but it shouldn't exit without EOF, no? And to circumvent SIGPIPE, can I use printf instead of echo? – TJJ May 23 at 0:47
  • cat could also be killed by SIGPIPE if trying to write to a pipe with no readers. That what happens in cat file | sed 1q. printf or echo makes no difference. If you want to keep a named pipe live for random readers & writers, you should "pin" it from another place, as I explained in 2nd part of my answer. – mosvy May 23 at 0:52
  • Ok, I'll have a look at that. But why does writing to the pipe stop at the first sleep command? – TJJ May 23 at 1:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.