打破HP-UX中“while read”循环读取的“tail -f”

时间:2008-12-04 04:14:20

标签: unix shell tail hp-ux

我正在尝试编写一个(sh -bourne shell)脚本,该脚本在将行写入文件时对其进行处理。我试图通过将tail -f的输出提供给while read循环来实现此目的。根据我在谷歌的研究以及this question处理类似问题,但使用bash,这种策略似乎是正确的。

从我读过的内容来看,当被跟踪的文件不再存在时,我似乎应该能够摆脱循环。它没有。事实上,似乎我可以摆脱这种情况的唯一方法是在另一个会话中杀死进程。 tail似乎确实工作正常,否则用这个测试:

touch file
tail -f file | while read line
do
  echo $line
done

我在另一个会话中附加到file的数据只显示在上面写的循环处理文件中。

这是在HP-UX B.11.23版上。

感谢您提供的任何帮助/见解!

5 个答案:

答案 0 :(得分:1)

如果你想突破,当你的文件不再存在时,就这样做:

 test -f file || break

将它放在你的循环中,应该会爆发。

剩下的问题是,如何打破读取线,因为这是阻塞。

这可以通过应用超时来完成,例如read -t 5行。然后每5秒读取一次,如果文件不再存在,循环将中断。注意:创建一个它可以处理大小写的循环,读取超时,但文件仍然存在。

编辑:似乎超时读取返回false,因此您可以将测试与超时结合起来,结果将是:

  tail -f test.file | while read -t 3 line || test -f test.file; do 
          some stuff with $line
  done

答案 1 :(得分:0)

我不知道HP-UX tail但GNU tail--follow=name选项,它将按名称跟踪文件(通过每隔几秒重新打开文件从相同的文件描述符读取,不会检测文件是否已取消链接),并在用于打开文件的文件名取消链接时退出:

tail --follow=name test.txt

答案 2 :(得分:0)

除非您使用GNU tail ,否则在跟踪文件时无法自行终止。 -f选项实际上仅用于交互式监视 - 实际上,我有一本书说-f“不太可能在shell脚本中使用”。

但是对于问题的解决方案,我并不完全确定这不是一种过度设计的方法,但我想你可以将 tail 发送到FIFO,然后有一个函数或脚本检查文件是否存在,并且如果它已被取消链接则终止它。

#!/bin/sh

sentinel ()
{
    while true
    do
        if [ ! -e $1 ]
        then
            kill $2
            rm /tmp/$1
            break
        fi
    done
}       

touch $1

mkfifo /tmp/$1

tail -f $1 >/tmp/$1 &

sentinel $1 $! &

cat /tmp/$1 | while read line
do
    echo $line
done

做了一些天真的测试,似乎可以正常工作,并且不会留下任何垃圾。

答案 3 :(得分:0)

我从来没有对这个答案感到满意,但我还没有找到替代方案:

kill $(ps -o pid,cmd --no-headers --ppid $$ | grep tail | awk '{print $1}')

获取当前进程的子进程,查找尾部,打印出第一列(尾部的pid)并将其终止。罪恶 - 确实很难看,就像生活一样。

答案 4 :(得分:0)

以下方法介绍tail -f file命令,将其进程ID和自定义字符串前缀(此处为 tailpid: )回显到while循环,其中带有自定义字符串前缀的行触发另一个(后台)while循环,每隔5秒检查file是否仍然存在。如果没有,tail -f file被杀死,包含背景while循环的子shell退出。

# cf. "The Heirloom Bourne Shell",
# http://heirloom.sourceforge.net/sh.html,
# http://sourceforge.net/projects/heirloom/files/heirloom-sh/ and
# http://freecode.com/projects/bournesh

/usr/local/bin/bournesh -c '
touch file
(tail -f file & echo "tailpid: ${!}" ) | while IFS="" read -r line
do
   case "$line" in
      tailpid:*) while sleep 5; do 
                       #echo hello; 
                       if [ ! -f file ]; then
                          IFS=" "; set -- ${line}
                          kill -HUP "$2"
                          exit
                       fi
                 done & 
                 continue ;;
   esac
   echo "$line"
done
echo exiting ...
'