Skip to content
Latchkey

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

Terminal
# 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.csv

Options

Flag / verbWhat it does
--csvCSV for both input and output
--icsv / --ojsonInput CSV, output JSON (and similar pairs)
--c2j / --c2pShorthand: CSV to JSON / CSV to pretty table
cut -f a,bKeep only named fields a and b
cut -o -f a,bKeep fields in the given order
filter '<expr>'Keep records where expr is true
thenChain 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.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →