突破“tail -f” 正在由“读取时”读取 HP-UX 中的循环

发布于 2024-07-09 22:25:29 字数 617 浏览 8 评论 0原文

我正在尝试编写一个(sh -bourne shell)脚本来处理写入文件的行。 我尝试通过将 tail -f 的输出输入到 while read 循环中来实现此目的。 根据我在 Google 的研究以及 这个问题处理类似的问题,但使用的是 bash。

根据我所读到的内容,当所跟踪的文件不再存在时,我似乎应该能够跳出循环。 事实并非如此。 事实上,似乎我能摆脱这种情况的唯一方法是在另一个会话中终止该进程。 tail 似乎工作正常,否则与此测试:

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

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

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

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

I'm trying to write a (sh -bourne shell) script that processes lines as they are written to a file. I'm attempting to do this by feeding the output of tail -f into a while read loop. This tactic seems to be proper based on my research in Google as well as this question dealing with a similar issue, but using bash.

From what I've read, it seems that I should be able to break out of the loop when the file being followed ceases to exist. It doesn't. In fact, it seems the only way I can break out of this is to kill the process in another session. tail does seem to be working fine otherwise as testing with this:

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

Data I append to file in another session appears just file from the loop processing written above.

This is on HP-UX version B.11.23.

Thanks for any help/insight you can provide!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

江南月 2024-07-16 22:25:29

如果您想突破,当您的文件不再存在时,只需执行以下操作:

 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

If you want to break out, when your file does not exist any more, just do it:

 test -f file || break

Placing this in your loop, should break out.

The remaining problem is, how to break the read line, as this is blocking.

This could you do by applying a timeout, like read -t 5 line. Then every 5 second the read returns, and in case the file does not longer exist, the loop will break. Attention: Create your loop that it can handle the case, that the read times out, but the file is still present.

EDIT: Seems that with timeout read returns false, so you could combine the test with the timeout, the result would be:

  tail -f test.file | while read -t 3 line || test -f test.file; do 
          some stuff with $line
  done
柏林苍穹下 2024-07-16 22:25:29

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

tail --follow=name test.txt

I don't know about HP-UX tail but GNU tail has the --follow=name option which will follow the file by name (by re-opening the file every few seconds instead of reading from the same file descriptor which will not detect if the file is unlinked) and will exit when the filename used to open the file is unlinked:

tail --follow=name test.txt
泡沫很甜 2024-07-16 22:25:29

除非您使用 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

做了一些简单的测试,它似乎工作正常,并且没有留下任何垃圾。

Unless you're using GNU tail, there is no way it'll terminate of its own accord when following a file. The -f option is really only meant for interactive monitoring--indeed, I have a book that says that -f "is unlikely to be of use in shell scripts".

But for a solution to the problem, I'm not wholly sure this isn't an over-engineered way to do it, but I figured you could send the tail to a FIFO, then have a function or script that checked the file for existence and killed off the tail if it'd been unlinked.

#!/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

Did some naïve testing, and it seems to work okay, and not leave any garbage lying around.

水染的天色ゝ 2024-07-16 22:25:29

我对这个答案一直不满意,但我也没有找到替代方案:

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

获取当前进程的子进程的所有进程,查找尾部,打印出第一列(尾部的 pid),然后杀死它。 罪孽极其丑陋,这就是生活。

I've never been happy with this answer but I have not found an alternative either:

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

Get all processes that are children of the current process, look for the tail, print out the first column (tail's pid), and kill it. Sin-freaking-ugly indeed, such is life.

故事灯 2024-07-16 22:25:29

以下方法将 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 ...
'

The following approach backgrounds the tail -f file command, echos its process id plus a custom string prefix (here tailpid:) to the while loop where the line with the custom string prefix triggers another (backgrounded) while loop that every 5 seconds checks if file is still existing. If not, tail -f file gets killed and the subshell containing the backgrounded while loop exits.

# 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 ...
'
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文