我正在尝试使用命名管道来监视正在运行的 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"
则会将其创建为常规文件。即使通过显式测试来查看它是否是管道,管道也有可能在测试和打开之间被移除。如果发生这种情况,read
s 将立即返回错误状态,因为该文件不包含数据。