问题
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?
回答1:
Just put the reading cycle into background (add & after done)?
回答2:
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
回答3:
You can use stty to set a timeout. IIRC its something like
stty -F $pipe -icanon time 0
来源:https://stackoverflow.com/questions/4874993/bash-script-with-non-blocking-read