Bash script with non-blocking read

无人久伴 提交于 2019-12-09 16:50:17

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!