Home > OS >  shell read seems to be getting newlines from file (fifo or regular)
shell read seems to be getting newlines from file (fifo or regular)

Time:04-23

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

CodePudding user response:

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.

CodePudding user response:

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

  • Related