![定期查看管道并提取自上次查看以来产生的新输出](https://linux22.com/image/129060/%E5%AE%9A%E6%9C%9F%E6%9F%A5%E7%9C%8B%E7%AE%A1%E9%81%93%E5%B9%B6%E6%8F%90%E5%8F%96%E8%87%AA%E4%B8%8A%E6%AC%A1%E6%9F%A5%E7%9C%8B%E4%BB%A5%E6%9D%A5%E4%BA%A7%E7%94%9F%E7%9A%84%E6%96%B0%E8%BE%93%E5%87%BA.png)
我正在读取管道不断增长的输出(例如 的输出inotifywait
)。
我需要定期检查管道输出并提取自上次查看以来产生的所有新输出。
如何在 shell 脚本中执行此操作?我不知道用于谷歌搜索的关键字。
答案1
管道中的数据只能读取一次; “新内容”部分很简单。只需使用 创建一个命名管道mkfifo
,将 inotifywait 输出重定向到它>
并定期读取管道。
更棘手的部分是读取管道,该管道在某处打开以供写入,而不会阻塞。 dd 可以做到这一点。
这是我用来创建并连续写入管道的设置:
mkfifo foo
( while true ; do date; sleep 1 ; done ) > foo
并读取所有未读数据:
dd iflag=nonblock if=foo bs=1M count=1 of=buffer.txt
您可以更改of=...
为您选择的输出文件。
迟早您会从管道中获得部分线路,因此请确保您的脚本可以处理此问题。对于您描述的活动类型,一个好的方法是在追加模式下重复 dd ,直到缓冲区以换行符终止:
buf=buffer.txt
pipe=foo
> $buf # empty the buffer
until [[ $( tail -c1 $buf | od -a ) == *nl* ]] # nl means newline
do
dd iflag=nonblock oflag=append conv=notrunc if=$pipe bs=1M count=1 of=$buf
ls -l $buf # see how it grows
sleep 1 # if the writer dies, this loop will be infinite and we don't want to kill the CPU
done
do_stuff.sh < $buf
# rm $buf
编辑:看来您想在终端处告诉 inotifywait 并转储所有新内容。这样更容易。创建一个类似于whatsnew.sh 的文件:
#!/bin/bash
echo "waiting for first output ... "
while true
do
n=0
while read -t0.1 line
do
echo "[$line]"
(( n++ ))
done
read -p "$n new lines. Press any key to try again... " -n1 -s </dev/tty
echo
done
然后启动它:
inotifywait | whatsnew.sh