1 (* Handy tool for managing CSV files.
2 * $Id: csvtool.ml,v 1.1 2005-05-24 13:52:50 rich Exp $
8 let cmd_cols ~separator ~csv ~chan cols =
9 let cols = List.map int_of_string cols in
11 let output = List.map (
13 let n = List.length row in
16 if 0 <= col_wanted && col_wanted < n then
17 List.nth row col_wanted
23 save_out ~separator chan output
25 let cmd_namedcols ~separator ~csv ~chan names =
28 | [] -> failwith "no rows in this CSV file"
30 let data = associate header data in
32 fun row -> List.map (fun name -> List.assoc name row) names
34 save_out ~separator chan data
36 let cmd_width ~csv ~chan () =
37 fprintf chan "%d\n" (columns csv)
39 let cmd_height ~csv ~chan () =
40 fprintf chan "%d\n" (lines csv)
42 let cmd_readable ~csv ~chan () =
43 save_out_readable chan csv
45 (* Process the arguments. *)
47 "csvtool - Copyright (C) 2005 Richard W.M. Jones, Merjis Ltd.
49 csvtool is a tool for performing manipulations on CSV files from shell scripts.
52 csvtool [-options] command [command-args] < input.csv
56 Return one or more columns from the CSV file. Columns are numbered
59 namedcol [name1] [name2] ...
60 Assuming the first row of the CSV file is a list of column headings,
61 this returned the column(s) with the named headings.
64 Return the maximum width of the CSV file (number of columns in the
68 Return the number of rows in the CSV file.
71 Print the input CSV in a readable format.
73 Input and output files:
74 csvtool normally processes its input from stdin and writes its output
75 to stdout. Use the -i and -o options to override this behaviour.
80 let input_sep = ref ',' in
81 let set_input_sep = function
82 | "TAB" -> input_sep := '\t'
83 | "COMMA" -> input_sep := ','
84 | s -> input_sep := s.[0]
87 let output_sep = ref ',' in
88 let set_output_sep = function
89 | "TAB" -> output_sep := '\t'
90 | "COMMA" -> output_sep := ','
91 | s -> output_sep := s.[0]
94 let input_file = ref "" in
95 let output_file = ref "" in
98 "-t", Arg.String set_input_sep,
99 "Input separator char. Use -t TAB for tab separated input.";
100 "-u", Arg.String set_output_sep,
101 "Output separator char. Use -t TAB for tab separated output.";
102 "-i", Arg.Set_string input_file,
103 "Read CSV input from file (instead of stdin)";
104 "-o", Arg.Set_string output_file,
105 "Write output to file (instead of stdout)"
113 Arg.parse argspec set_rest usage;
115 let input_sep = !input_sep in
116 let output_sep = !output_sep in
117 let input_file = !input_file in
118 let output_file = !output_file in
119 let rest = List.rev !rest in
123 | [] -> prerr_endline (Sys.executable_name ^ " --help for usage"); exit 1
126 (* Read the input file. *)
128 if input_file <> "" then load ~separator:input_sep input_file
129 else load_in ~separator:input_sep stdin in
131 (* Set up the output file. *)
133 if output_file <> "" then open_out output_file
138 cmd_cols ~separator:output_sep ~csv:input ~chan args
139 | "namedcol" | "namedcols" ->
140 cmd_namedcols ~separator:output_sep ~csv:input ~chan args
142 cmd_width ~csv:input ~chan ()
144 cmd_height ~csv:input ~chan ()
146 cmd_readable ~csv:input ~chan ()
147 | _ -> prerr_endline (Sys.executable_name ^ " --help for usage")
150 if output_file <> "" then close_out chan