2008-12-04 89 views
0

我试图编写一个(sh -bourne shell)脚本,它们在写入文件时处理行。我试图通过将tail -f的输出提供给while read循环来完成此操作。基于我在Google中的研究以及处理类似问题的this question,这种策略似乎是正确的,但使用bash。突破HP-UX中“while read”循环读取的“tail -f”

从我读过的文字看来,我应该能够在跟随的文件不存在时跳出循环。它没有。事实上,似乎我能摆脱这种情况的唯一方法就是在另一个会话中杀死进程。 tail似乎要被罚款,否则工作作为检验本:

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

数据我追加到file在另一个会话似乎刚刚从上面写的循环处理文件。

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

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

回答

0

我不知道HP-UX tail但GNU tail--follow=name选项,将遵循文件名的文件(通过重新打开文件每隔几秒钟,而不是从它不会检测到相同的文件描述符阅读如果该文件是未链接),并且将退出时用来打开文件的文件名未链接:

tail --follow=name test.txt 
+0

嗨罗伯特。我在Google搜索中看到了这个选项,听起来像是最好的选择。遗憾的是,HP-UX不支持此选项。 – AgentConundrum 2008-12-04 04:39:55

+0

@代理 - 你可以下载和编译(端口)GNU尾巴?它当然似乎是你想要的。 – tvanfosson 2008-12-04 04:47:36

1

如果你想打出来,当你的文件不存在了,只是做:

test -f file || break 

Placin g在你的循环中,应该爆发。

剩下的问题是,如何中断读取行,因为这是阻塞。

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

编辑:似乎与超时read返回假的,所以你可以测试与超时相结合,其结果必然是:

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

除非你使用GNU ,也没办法在跟踪文件时它会自行终止。 -f选项实际上仅用于交互式监视 - 实际上,我有一本书说,-f“不可能在shell脚本中使用”。

但是对于问题的解决方案,我不完全确定这不是一个过度设计的方法,但我想你可以发送尾部到一个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 

做了一些天真的测试,它似乎工作还好,并没有留下任何垃圾乱丢。

0

我从来没有满意这个答案,但我还没有找到一种替代或者:

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

获取是当前进程的所有子进程,寻找尾巴,打印出的第一列(尾巴的pid),并杀死它。确实有罪恶 - 丑陋,这就是生活。

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 ... 
'