2014-03-03 48 views
1

我有許多行的文本文件。我想寫一個簡單的OCaml程序,它可以逐行處理這個文件,也許可以打印這行。OCaml - 致命錯誤:使用`| |時發生異常Sys_error(「Broken pipe」)|頭上`包含很多行輸出

爲了編寫這個程序,我首先創建了一個較小的文件,使用更少的行 - 這樣程序就能夠更快地完成執行。

$ 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_lines將此文件句柄作爲參數。

process_lines使用可選參數ix來計算行號,因爲它從行中讀取文件句柄。 process_lines只是將從file_handle讀取的行打印到標準輸出。

然後,當我在較小的輸入文件和管道執行程序輸出到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程序會發生這樣的水管壞了的錯誤)已經完成了寫作G。這就是爲什麼如果我使用tail命令作爲讀者,我永遠不會得到這樣的錯誤。

但是,當文件的行數較少時,爲什麼沒有發生斷管錯誤?

回答

2

破管信號是Unix設計的基本部分。當你有一個管道a | b其中b只讀取少量的數據,你不希望a浪費它的時間寫b已經閱讀了它所需要的一切。爲了做到這一點,Unix將破損的管道信號發送到一個進程,該進程寫入沒有人正在讀取的管道。在通常情況下,這會導致程序以無聲方式退出(即殺死程序),這正是您想要的。

在這個假設的例子中,b在讀完幾行後退出,這意味着沒有人正在讀取管道。下次a試圖寫入更多的輸出時,它會發送斷開的管道信號並退出。

在你的情況下,a是你的程序和bhead

它看起來OCaml運行時注意到信號,並沒有默默退出。你可以認爲這是一個缺陷,或者當信號終止你的程序時知道它是很好的。解決這個問題的最好方法是自己捕捉信號並靜靜地退出。

小文件沒有發生的原因是整個輸出適合管道。 (一個管道代表一個64K字節左右的緩衝區。)您的程序只是寫入其數據並退出;沒有足夠的時間讓程序嘗試寫入沒有閱讀器的管道。

相關問題