Miller (mlr): cut and filter CSV/TSV Records
mlr treats CSV/TSV/JSON rows as keyed records, so mlr --csv cut -f name,age selects columns by name and filter keeps rows by a condition.
awk works on positional fields; Miller works on named fields with a header, which is far less brittle when columns move. Verbs chain with then.
What it does
mlr applies a chain of verbs to record-structured data. cut -f selects named columns, filter keeps records matching a boolean expression, and then pipes one verb into the next. Input/output format is set by flags like --csv or --c2j.
Common usage
# select two columns from a CSV
mlr --csv cut -f name,email data.csv
# filter rows then select columns
mlr --csv filter '$status == "active"' then cut -f id,name data.csv
# CSV in, JSON out
mlr --icsv --ojson cat data.csvOptions
| Flag / verb | What it does |
|---|---|
| --csv | CSV for both input and output |
| --icsv / --ojson | Input CSV, output JSON (and similar pairs) |
| --c2j / --c2p | Shorthand: CSV to JSON / CSV to pretty table |
| cut -f a,b | Keep only named fields a and b |
| cut -o -f a,b | Keep fields in the given order |
| filter '<expr>' | Keep records where expr is true |
| then | Chain the next verb |
In CI
Parse a tool that emits CSV (test timings, coverage rows) and gate on it: mlr --csv filter '$coverage < 80' report.csv prints offending rows, and a non-empty result can fail the job. Named fields mean the check survives column reordering in the report.
Common errors in CI
mlr: command not found means Miller is not installed (apt-get install miller or brew install miller; the binary is mlr, not miller). mlr: CSV header/data length mismatch means a data row has more or fewer fields than the header, often a stray comma; add --allow-ragged-csv-input. Referencing $Name when the header says name silently yields absent values, so match case exactly.