1

多くの行を含むテキスト ファイルがあります。このファイルを行ごとに処理し、行を出力する簡単な 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_linesこのファイル ハンドルを引数として再帰関数を呼び出します。

process_linesオプションの引数ixを使用して、ファイルハンドルから行ごとに読み取るときに行番号をカウントします。process_lines は、 から読み取った行をfile_handle標準出力に出力するだけです。

次に、小さな入力ファイルでプログラムを実行し、出力を Linuxheadコマンドにパイプすると、すべて正常に動作します。

$ ./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コマンドをリーダーとして使用した場合、そのようなエラーが発生しないのはそのためです。

しかし、ファイルの行数が少ないのに、パイプの破損エラーが発生しなかったのはなぜですか?

4

1 に答える 1

2

壊れたパイプ シグナルは、Unix 設計の基本的な部分です。少量のデータのみを読み取るパイプラインa | bがある場合、必要なデータをすべて読み取った後で書き込みに時間を無駄にしたくはありません。これを実現するために、Unix は壊れたパイプ シグナルを、誰も読み取っていないパイプに書き込むプロセスに送信します。通常、これによりプログラムは黙って終了します (つまり、プログラムを強制終了します)。bab

この架空の例でbは、数行を読み取った後に終了します。これは、誰もパイプを読み取っていないことを意味します。次回aさらに出力を書き込もうとすると、壊れたパイプ信号が送信されて終了します。

あなたの場合aはあなたのプログラムであり、bですhead

OCaml ランタイムがシグナルに気づき、黙って終了していないようです。これを欠陥と見なすこともできますし、信号によってプログラムが終了したときにいつでも知ることができると便利かもしれません。これを修正する最善の方法は、自分でシグナルをキャッチして、黙って終了することです。

小さなファイルで発生しない理由は、出力全体がパイプに収まるためです。(パイプは 64K バイト程度のバッファーを表します。) プログラムはデータを書き込んで終了します。プログラムがリーダーなしでパイプに書き込もうとするのに十分な時間がありません。

于 2014-03-03T03:33:08.313 に答える