OCaml-致命错误:在包含多行的输出上使用“head”时出现异常系统错误(“断管”)

OCaml-致命错误:在包含多行的输出上使用“head”时出现异常系统错误(“断管”),ocaml,broken-pipe,Ocaml,Broken Pipe,我有很多行的文本文件。我想写一个简单的OCaml程序,可以逐行处理这个文件,也可以打印出来 为了编写这个程序,我首先创建了一个较小的文件,具有较少的行,这样程序将更快地完成执行 $ wc -l input/master 214745 input/master $ head -50 input/master > input/small-master 下面是我编写的简单样板filter.ml程序: open Core.Std;; open Printf;; open Core.In_cha

我有很多行的文本文件。我想写一个简单的OCaml程序,可以逐行处理这个文件,也可以打印出来

为了编写这个程序,我首先创建了一个较小的文件,具有较少的行,这样程序将更快地完成执行

$ wc -l input/master 
214745 input/master
$ head -50 input/master > input/small-master
下面是我编写的简单样板
filter.ml
程序:

open Core.Std;;
open Printf;;
open Core.In_channel;;

if Array.length Sys.argv >= 2 then begin
  let rec process_lines ?ix master_file  =
    let ix = match ix with
      | None -> 0
      | Some x -> x
    in
    match input_line master_file with
    | Some line -> (
      if ix > 9 then printf "%d == %s\n" ix line;
      process_lines ~ix:(ix+1) master_file
    )
    | None -> close master_file
  in
  let master_file = create Sys.argv.(1) in
    process_lines master_file
end
它将输入文件的位置作为命令行参数,创建用于读取此文件的文件句柄,并使用此文件句柄作为参数调用递归函数
process\u lines

process\u lines
使用可选参数
ix
在逐行读取文件句柄时计算行号。process_lines只需将从
文件\u句柄
读取的行打印到标准输出

然后,当我在较小的输入文件上执行程序,并将输出传输到Linux
head
命令时,一切正常:

$ ./filter.native input/small-master |head -2
10 == 1000032|BINCH JAMES G|4|2012-11-13|edgar/data/1000032/0001181431-12-058269.txt
11 == 1000032|BINCH JAMES G|4|2012-12-03|edgar/data/1000032/0001181431-12-061825.txt
当我在较大的文件上执行程序时,我会看到一个断管错误:

$ ./filter.native input/master |head -2
10 == 1000032|BINCH JAMES G|4|2012-11-13|edgar/data/1000032/0001181431-12-058269.txt
11 == 1000032|BINCH JAMES G|4|2012-12-03|edgar/data/1000032/0001181431-12-061825.txt
Fatal error: exception Sys_error("Broken pipe")
Raised by primitive operation at file "pervasives.ml", line 264, characters 2-40
Called from file "printf.ml", line 615, characters 15-25
Called from file "find.ml", line 13, characters 21-48
Called from file "find.ml", line 19, characters 2-27
我了解到,当管道的读取器(
head
在本例中是命令)在管道的编写器(在本例中是我的OCaml程序)完成写入之前退出时,就会发生这种断管错误。这就是为什么如果我使用
tail
命令作为读卡器,我永远不会得到这样的错误


但是,当文件的行数较少时,为什么没有出现断管错误?

断管信号是Unix设计的基本部分。当管道
a | b
b
只读取少量数据时,您不希望
a
b
读取所有需要的数据后浪费时间进行写入。为了实现这一点,Unix将断开的管道信号发送到一个进程,该进程将写入一个没有人读取的管道。在通常情况下,这会导致程序以静默方式退出(即,它会终止程序),这正是您想要的

在这个假设的示例中,
b
在读取几行后退出,这意味着没有人在读取管道。下次
a
尝试写入更多输出时,它会收到断管信号并退出

在您的情况下,
a
是您的程序,
b
head

OCaml运行时似乎注意到了该信号,并且没有悄悄退出。你可以认为这是一个缺陷,或者当信号已经终止你的程序时,它是很好的。解决这个问题的最好办法是自己捕捉信号,然后静静地离开

对于小文件,这种情况不会发生的原因是整个输出适合管道。(管道代表64K字节左右的缓冲区。)您的程序只需写入数据并退出;没有足够的时间让程序尝试在没有读取器的情况下写入管道