Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash script with non-blocking read

I want to send some data to a root process with a named pipe. Here is the script and it works great:

#!/bin/sh
pipe=/tmp/ntp

if [[ ! -p $pipe ]]; then
    mknod -m 666 $pipe p
fi

while true
do
    if read line <$pipe; then
         /root/netman/extra/bin/ntpclient -s -h $line > $pipe 2>&1
    fi
done

I actually have several script like this one. I would like to enclose all of them in a single script. The problem is that execution blocks on the first "read" and I cannot execute multiple "reads" in a single process. Isn't there anything I can do? Is it possible to have a "non-blocking" bash read?

like image 409
michelemarcon Avatar asked Feb 02 '11 13:02

michelemarcon


People also ask

What is $@ in bash script?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

What is $() in bash?

$() means: "first evaluate this, and then evaluate the rest of the line". Ex : echo $(pwd)/myFile.txt. will be interpreted as echo /my/path/myFile.txt. On the other hand ${} expands a variable.

What does != Mean in shell script?

And the != operator means 'is not equal to', so [ $? != 0 ] is checking to see if $? is not equal to zero. Putting all that together, the above code checks to see if the grep found a match or not.

Does bash ignore whitespace?

Bash uses whitespace to determine where words begin and end. The first word is the command name and additional words become arguments to that command.


1 Answers

Bash's read embedded command has a -t parameter to set a timeout:

-t timeout
    Cause read to time out and return failure if a complete line of input is not
    read within timeout seconds. This option has no effect if read is not reading
    input from the terminal or a pipe.

This should help you solve this issue.

Edit:

There are some restrictions for this solution to work as the man page indicates: This option has no effect if read is not reading input from the terminal or a pipe.

So if I create a pipe in /tmp:

mknod /tmp/pipe p

Reading directly from the pipe is not working:

$ read -t 1 </tmp/pipe  ; echo $?

Hangs forever.

$ cat /tmp/pipe | ( read -t 1 ; echo $? )
1

It is working but cat is not exiting.

A solution is to assign the pipe to a file descriptor:

$ exec 7<>/tmp/pipe

And then read from this file descriptor either using redirection:

$ read -t 1 <&7  ; echo $?
1

Or the -u option of read:

$ read -t 1 -u 7  ; echo $?
1
like image 95
gabuzo Avatar answered Oct 06 '22 02:10

gabuzo