Command-Line & Systems Programming

Generates --help man pages automatically; supports subcommands with Cmd.group.

42.1 Sys.argv

let () =
  match Array.to_list Sys.argv with
  | [_; name] -> Printf.printf "Hello, %s\n" name
  | prog :: _ -> Printf.eprintf "usage: %s NAME\n" prog; exit 1
  | [] -> exit 1

42.2 Arg (stdlib)

let verbose = ref false
let count = ref 1
let files = ref []

let spec = [
  ("-v", Arg.Set verbose, " Verbose output");
  ("-n", Arg.Set_int count, "N Repeat N times");
]

let () =
  Arg.parse (Arg.align spec) (fun f -> files := f :: !files) "usage: prog [-v] [-n N] files...";
  List.iter print_endline (List.rev !files)

42.3 Cmdliner (recommended)

Generates --help man pages automatically; supports subcommands with Cmd.group.

open Cmdliner

let greet name times loud =
  for _ = 1 to times do
    let msg = "Hello, " ^ name in
    print_endline (if loud then String.uppercase_ascii msg else msg)
  done

let name = Arg.(value & pos 0 string "World" & info [] ~docv:"NAME")
let times = Arg.(value & opt int 1 & info ["n"; "times"] ~doc:"Repeat count")
let loud = Arg.(value & flag & info ["l"; "loud"] ~doc:"Shout")

let cmd =
  Cmd.v (Cmd.info "greet" ~version:"1.0" ~doc:"Greet someone")
    Term.(const greet $ name $ times $ loud)

let () = exit (Cmd.eval cmd)

42.4 The Unix library

(executable (name main) (libraries unix))
Unix.getpid (), Unix.getcwd (), Unix.gettimeofday ()
Unix.sleepf 0.5
Unix.stat "file" |> fun st -> st.Unix.st_size
Unix.mkdir "dir" 0o755, Unix.unlink "f", Unix.opendir, Unix.readdir

(* Running a process and reading its output *)
let run cmd =
  let ic = Unix.open_process_in cmd in
  let out = In_channel.input_all ic in
  ignore (Unix.close_process_in ic); out

(* fork / exec (Unix-like systems) *)
match Unix.fork () with
| 0 -> Unix.execvp "ls" [| "ls"; "-l" |]
| pid -> ignore (Unix.waitpid [] pid)

(* Sockets *)
let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0
Unix.connect sock (Unix.ADDR_INET (Unix.inet_addr_loopback, 8080))
Unix.select, Unix.pipe, Unix.dup2, Unix.signal handling via Sys.set_signal

42.5 Useful systems libraries

bos (OS interaction), fpath (paths), fileutils, logs (logging), mtime (monotonic time), ptime (POSIX time), timedesc, progress (progress bars), notty / minttea (TUIs), spawn, feather (shell scripting).

(* Logs *)
let () =
  Logs.set_reporter (Logs_fmt.reporter ());
  Logs.set_level (Some Logs.Info);
  Logs.info (fun m -> m "Started with %d workers" 4)