连续轮询命名 (FIFO) 管道

连续轮询命名 (FIFO) 管道

我正在尝试使用命名管道来监视正在运行的 shell 脚本的活动。该 shell 脚本将向管道写入它已“开始”处理的信息。当它完成处理时,它将向管道写入“Completed”。第二个脚本将执行监视并读取两条消息。如果第二个脚本在 5 分钟内未收到“已完成”消息,则会发送警报。

所以我从 Linux Journal 上找到了这段关于使用命名管道在两个进程之间进行通信的代码。我立即尝试从管道中获取两条消息,并在循环过程中显示一个计数器,但如果出现“已完成”消息,则重置回 0。接下来将添加计时,因为我想确保它将不断轮询管道以获取下一条消息。但是,我没有看到计数器增量。看起来它正在等待管道的读取行。关于我做错了什么有什么建议吗?

#!/bin/bash

pipe=/tmp/testpipe

loopcnt=0
while true
do
    echo "count: $loopcnt"

    if read line <$pipe; then
        if [[ "$line" == 'Started' ]]; then
            echo $line
        elif [[ "$line" == 'Completed' ]]; then
            echo $line
            loopcnt=0
        fi
    fi
    ((loopcnt=loopcnt+1))
done

答案1

如果管道的写入端未打开,则打开读取端将阻塞,直到写入器出现。当 shell 在自己运行之前尝试设置重定向时,就会发生这种情况,因此with 的read超时本身没有帮助。read-t

不过,如果您向管道写入任何内容,循环应该继续进行,但这无助于找出经过了多少时间,更不用说检测在读取数据之前是否经过了太多时间。

解决这个问题的最简单方法是在读取器中以读写模式打开管道,确保始终有写入器。

例如这样的事情:

#!/bin/bash

pipe=/tmp/testpipe
if ! [[ -p "$pipe" ]]; then
    echo "'$pipe' isn't a pipe"
    exit 1
fi
exec 3<> "$pipe"
secs=0
timeout=5
while true; do
    if read -t 1 -u 3 line; then
        echo "read '$line'"
        secs=0
    else
        echo .
    fi
    if ((++secs >= timeout)); then
        echo "no data within $timeout secs"
        break
    fi
done
echo end.

但请注意,如果$pipe不存在,exec 3<> "$pipe"则会将其创建为常规文件。即使通过显式测试来查看它是否是管道,管道也有可能在测试和打开之间被移除。如果发生这种情况,reads 将立即返回错误状态,因为该文件不包含数据。

相关内容