1

我想在命名管道上运行 tail 以促进一些二进制日志文件处理。问题是神秘数据被添加到流的开头。我通过使用打开的端口 (open_port) 启动 erlang 进程来运行我的测试,然后我使用另一个 shell 将 bin 放入命名管道中。

这是一个从端口获取数据的简单函数:

bin_from_tail() ->
  open_port({spawn,"/usr/bin/tail -F named_pipe"},
                             [binary,in,eof]),
  receive
  {_,{data,<<Data/binary>>}} -> Data
  end.

所以这里有两种方法让我获取相同的数据......

  1. 创建命名管道

    mkfifo named_pipe

  2. 此命令会一直阻塞,直到您从另一个 shell 运行“cat log.bin > named_pipe”

    {ok,TailBin} = 文件:read_file(log.bin)。

  3. 使用 erlang 文件库 FileBin = file:read_file(log.in) 将整个文件读入内存。

但是 TailBin 和 FileBin 是不一样的!TailBin 开头有一个神秘的 120 字节字符串:

<<40,6,161,69,172,216,56,14,100,0,80,6,0,0,0>>
4

2 回答 2

2

感谢关于无休止循环猫/重启死端口的想法。似乎命名管道只是缓冲了一点点,所以如果端口打开得足够快,编写器进程(另一个程序)就不会崩溃!绝对有风险的东西,但就黑客而言......它有效。

因为刚才说的所有邮件列表帖子都这样做,没有示例就这样做,我将发布我的工作原理!如果有人想提供改进,请随时这样做。我的解决方案:

read() ->
  Port = open_port({spawn,"/bin/cat /path/to/pipe"},
                   [binary,in,eof]),
  do_read(Port).

do_read(Port) ->
  receive
    {Port,{data,<<Data/binary>>}} ->
      case do_something:with(Data) of
        ok ->
          io:format("G") % Good
        Any ->
          io:format("B") % Bad
      end;
    {Port,eof} ->
      read();
    Any ->
      io:format("No match fifo_client:do_read/1, ~p~n",[Any])
  end,
  do_read(Port).
于 2010-05-05T16:40:37.097 回答
1

我发现在 erlang 之外也发生了同样的事情。问题是tail试图向您显示文件的结尾,而不是整个文件。如果您在普通文件上使用它,则写入的任何内容都是新的,并由-f拾取,但在这种情况下,看起来tail正在等到文件末尾(通过管道的 eof )然后显示最后 10 行(将二进制文件视为文本)。

tail -F -c 9999999

(假设您的日志为 9999999 字节或更少)可能会起作用。

也许尝试使用cat而不是tail -F,这似乎对我有用。然后你只需要避免cat在 eof 时退出的事实,我假设你试图通过使用 tail 来避免这种情况。

所以一个shell脚本可以无限循环cat,也许吧?

或者让 erlang 重新启动关闭并在端口死亡时重新创建端口,因为无论如何您都会收到 eof 信号。或者在进程退出时使用 exit_status 标志来向 open_port 发出信号,以防您需要区分 eof 和进程退出。(如果你同时使用exit_status和eof,eof永远不会出现,用cat < /dev/null的简短测试表明)

于 2010-04-29T12:10:39.030 回答