'shell read seems to be getting newlines from file (fifo or regular)

What I want to achieve is to have a shell script hooked up onto a fifo and react to certain commands that would read out (with the usual read command). Now this seems trivial but , by my surprise, the read command does not react as I expected it to. See following simple script :

#!/bin/bash

while true; do
        read ONE_SENTENCE
        echo Simon says : ${ONE_SENTENCE}
        sleep 1
done

I launch this by "./test.sh < in.pipe", where in.pipe is "mkfifo in.pipe"

Now, if I write sthing in the pipe with "echo test1 > in.pipe" I get the following result :

stc@host:~$ ./test.sh < in.pipe 
Simon says : test1
Simon says :
Simon says :
Simon says :
Simon says :
Simon says :
Simon says :
Simon says :

In other words, read doesn't block, it find always sthing to read out. What am I missing ? Obviously, I want read to block until new data



Solution 1:[1]

The key is to only output ONE_SENTENCE upon a successful read, e.g.

while :; do
  if read ONE_SENTENCE; then
    [ "$ONE_SENTENCE" = quit ] && break          ## convenient quit ability
    printf "Simon says : %s\n" "$ONE_SENTENCE"   ## output only on good read
  fi
  sleep 1
done

No output from the pipe is produced except on a valid read of a line from the fifo.

A slight variation that conveniently sets the fifo up for you and deletes it on script exit. (upper-case variables are avoided below)

#!/bin/bash

pipe=in.pipe

trap "rm -r $pipe" EXIT

[ -p "$pipe" ] || mkfifo "$pipe"

while :; do
  if read line; then
    [ "$line" = quit ] && break
    printf "Simon says : %s\n" "$line"
  fi
  sleep .5
done < "$pipe"

The script does the exact same thing (other than a 1/2 sec sleep, but it creates the fifo and sets a trap to remove it before entering the read-loop.

Solution 2:[2]

Many thx for the answer. In the meanwhile I've managed to get what I wanted this way

#!/bin/bash

while true; do
    read ONE_SENTENCE < in.pipe
    echo Simon says : ${ONE_SENTENCE}
    sleep 1
done

The above code blocks (as expected)... but I still don't understand why the first script didn't block... anyways, one way or the other, it works

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 David C. Rankin
Solution 2 Thomas