miller - 命名索引数据处理器
技能脚本入口
本技能附带两套等价包装脚本(Unix .sh + Windows PowerShell .ps1),提供友好子命令入口与安装自检,免去记忆原始参数。
macOS / Linux(bash):
bash scripts/miller-skill.sh <subcommand> [args...]
# 查看完整用法与示例
bash scripts/miller-skill.sh help
Windows(PowerShell):
.\scripts\miller-skill.ps1 <subcommand> [args...]
# 若被执行策略拦截,用下面这种调用绕过:
powershell -ExecutionPolicy Bypass -File scripts\miller-skill.ps1 <subcommand> [args...]
可用子命令: convert、cut、rename、reorder、put、filter、sort、join、reshape、uniq、sample、head、tail、count
脚本选择规则: macOS / Linux 用 .sh;Windows 用 .ps1。两者子命令完全一致。
脚本仅作便捷封装,最终调用系统的
miller二进制;运行前请确保已安装对应工具(安装方式见下文各节)。说明:SkillHub 不支持.cmd/.bat文件类型,故不附带 Windows cmd 版;无 PowerShell 的环境可用 Git Bash 运行.sh版。个别依赖 Unix 管道工具的子命令(如 gron 的sed/fzf)在 Windows 下建议用 Git Bash 运行.sh版。
这是什么
Miller (mlr) (johnkerl/miller, 8.1k ⭐) 是面向 命名索引数据 (CSV、TSV、JSON、JSONL、DKVP) 的类 awk/sed/cut/join/sort 工具。核心优势:按列名而非位置操作、流式处理 (常数内存)、格式保真转换、单二进制 (C 语言,极快)。
- GitHub: https://github.com/johnkerl/miller
- 文档: https://miller.readthedocs.io/
- 适合:ETL 管道、日志处理、数据清洗、格式转换、流式聚合
何时使用我
当用户出现以下意图时加载此技能:
- "miller"、"mlr 命令"、"处理 csv/json 按列名"
- "awk 但按列名"、"sed 但按字段名"
- "流式处理大文件"、"常数内存处理 GB 级数据"
- "CSV 转 JSON"、"JSON 转 CSV"、"TSV 转 JSONL" 等格式互转
- "按字段名切片/重排/重命名/计算新列"
- "分组聚合 (group-by)"、"多键连接 (join)"
- "正则提取/替换字段值"
- "数据清洗管道"、"ETL 脚本"
核心能力
1. 格式转换 (保真、流式)
# CSV -> JSON (数组)
mlr --csv --json cat data.csv > data.json
# CSV -> JSON Lines (流式,大文件首选)
mlr --csv --jsonl cat data.csv > data.jsonl
# JSON -> CSV
mlr --json --csv cat data.json > data.csv
# TSV -> JSON
mlr --tsv --json cat data.tsv > data.json
# DKVP (键值对格式) 互转
mlr --dkvp --csv cat data.dkvp > data.csv
# 自动检测格式 (大多数情况)
mlr --icsv --ojson cat data.csv > data.json
2. 列操作 (按名而非位置)
# 选择列 (保留顺序)
mlr --csv cut -f name,age,email data.csv
# 排除列
mlr --csv cut -x -f ssn,password data.csv
# 重排列顺序
mlr --csv cut -f email,name,age data.csv
# 重命名列
mlr --csv rename old_name,new_name data.csv
mlr --csv rename 'first_name,given_name;last_name,surname' data.csv
# 移动列位置
mlr --csv reorder -f id,name,* data.csv # id,name 在前,其余保持
mlr --csv reorder -e -f ssn data.csv # ssn 移到最后
3. 计算新列 (put/filter)
# 算术表达式
mlr --csv put '$total = $price * $qty' data.csv
# 字符串操作
mlr --csv put '$full = $first . " " . $last' data.csv
mlr --csv put '$email_domain = gsub($email, ".*@", "")' data.csv
# 条件表达式
mlr --csv put '$tier = if($amount > 1000, "premium", "standard")' data.csv
# 日期时间
mlr --csv put '$days_old = (now() - strptime($created, "%Y-%m-%d")) / (24*3600)' data.csv
# 正则提取
mlr --csv put '$domain = regex_replace($url, "https?://([^/]+).*", "\\1")' data.csv
# 多语句 (分号分隔)
mlr --csv put '
$ratio = $sales / $target;
$status = if($ratio >= 1, "met", "missed")
' data.csv
4. 行过滤 (filter)
# 简单条件
mlr --csv filter '$status == "active"' data.csv
# 复合条件
mlr --csv filter '$age >= 18 && $country == "US"' data.csv
# 正则匹配
mlr --csv filter '$email =~ "@gmail\\.com$"' data.csv
# 数值范围
mlr --csv filter '$score >= 60 && $score <= 100' data.csv
# 空值检查
mlr --csv filter 'is_present($email) && $email != ""' data.csv
# 采样 (伯努利/水库)
mlr --csv sample -k 100 data.csv # 固定 100 行
mlr --csv sample -p 0.1 data.csv # 10% 概率
5. 排序
# 单列排序
mlr --csv sort -f name data.csv
# 多列排序
mlr --csv sort -f department, -nr salary data.csv # 部门升序,薪资降序
# 自然排序 (版本号等)
mlr --csv sort -n version data.csv
6. 分组聚合 (stats1/stats2)
# 单键分组聚合
mlr --csv stats1 -a sum,mean,count -f amount -g category data.csv
# 多键分组
mlr --csv stats1 -a min,max,mean -f price -g region,product data.csv
# 多字段聚合
mlr --csv stats1 -a sum,count -f revenue,quantity -g year,month data.csv
# 统计所有数值列
mlr --csv stats1 -a sum,mean,stddev,min,max data.csv
# 计数去重
mlr --csv stats1 -a count -f * -g category data.csv
7. 连接 (join)
# 内连接 (默认)
mlr --csv join -j id -l users.csv -r orders.csv
# 左连接
mlr --csv join -j id --ul users.csv --ur orders.csv
# 多键连接
mlr --csv join -j "user_id,date" -l daily.csv -r monthly.csv
# 字段重命名避免冲突
mlr --csv join -j id -l users.csv -r orders.csv --prefix r_
8. 重塑 (reshape)
# 宽表 -> 长表 (melt)
mlr --csv reshape -r "^qtr" -o item,value data.csv
# 输入: id,qtr1,qtr2,qtr3,qtr4
# 输出: id,item,value (item=qtr1/qtr2...)
# 长表 -> 宽表 (pivot)
mlr --csv reshape -s item,value data.csv
# 输入: id,item,value
# 输出: id,qtr1,qtr2,qtr3,qtr4
9. 去重与唯一化
# 去重 (全行)
mlr --csv uniq data.csv
# 按键去重 (保留首行)
mlr --csv uniq -g id data.csv
# 计数去重
mlr --csv uniq -c data.csv
10. 正则提取/替换 (gsub/regex_replace)
# 字段级替换
mlr --csv put '$phone = gsub($phone, "[^0-9]", "")' data.csv
# 全记录替换 (sed 风格)
mlr --csv put -q 'for (k, v in $*) { $[k] = gsub(v, "old", "new") }' data.csv
# 正则捕获组提取新列
mlr --csv put '$year = regex_replace($date, "(\\d{4})-\\d{2}-\\d{2}", "\\1")' data.csv
典型工作流示例
场景 1:日志 ETL 管道 (流式,常数内存)
# 1. JSON Lines 日志 -> CSV,提取字段、过滤、计算
cat app.log.jsonl | \
mlr --jsonl --csv \
cut -f timestamp,level,service,message,latency_ms \
then filter '$level == "ERROR" || $latency_ms > 1000' \
then put '$date = strftime(strptime($timestamp, "%Y-%m-%dT%H:%M:%S"), "%Y-%m-%d")' \
then stats1 -a count,mean -f latency_ms -g date,service \
> daily_error_latency.csv
场景 2:多源数据标准化合并
# 1. 统一字段名
mlr --csv rename 'user_id,id;full_name,name' source1.csv > s1.csv
mlr --csv rename 'customer_id,id;customer_name,name' source2.csv > s2.csv
# 2. 统一格式为 JSONL
mlr --csv --jsonl cat s1.csv > s1.jsonl
mlr --csv --jsonl cat s2.csv > s2.jsonl
# 3. 合并去重
cat s1.jsonl s2.jsonl | mlr --jsonl uniq -g id > merged.jsonl
# 4. 转回 CSV 供下游
mlr --jsonl --csv cat merged.jsonl > final.csv
场景 3:销售数据分组分析
# 1. 按区域+产品聚合
mlr --csv stats1 \
-a sum,mean,count,min,max \
-f revenue,units \
-g region,product \
sales.csv | \
mlr --csv sort -f region,-nr sum_revenue > regional_summary.csv
# 2. 算占比
mlr --csv put '
$total = sum_revenue;
$pct = $sum_revenue / $total * 100
' regional_summary.csv > regional_with_pct.csv
场景 4:宽表长表互转 (报表 <-> 分析)
# 月度列 -> 长表 (便于绘图/透视)
mlr --csv reshape -r "^month_" -o month,value wide_report.csv > long_data.csv
# 长表 -> 宽表 (生成报表)
mlr --csv reshape -s month,value long_data.csv > wide_report.csv
场景 5:数据清洗标准化
mlr --csv \
cut -x -f internal_id,debug_flag \
then rename 'cust_name,name;cust_email,email' \
then put '
$email = lower($email);
$phone = gsub($phone, "[^0-9]", "");
$created = strftime(strptime($created, "%m/%d/%Y"), "%Y-%m-%d")
' \
then filter 'is_present($email) && $email != ""' \
then sort -f created \
dirty.csv > clean.csv
场景 6:JSON/JSONL 处理 (配合 jq)
# JSON 数组 -> JSONL (流式)
mlr --json --jsonl cat data.json > data.jsonl
# JSONL 处理后 -> JSON 数组
mlr --jsonl --json cat processed.jsonl > output.json
# 复杂 JSON 提取 (用 put 的递归能力)
mlr --jsonl put '$user_name = $user.profile.name' events.jsonl
常用动词速查表
| 动词 | 说明 | 关键参数 |
|------|------|----------|
| cat | 格式转换/透传 | --icsv --ojson 等 |
| cut | 选列/排除列 | -f fields, -x 排除 |
| rename | 重命名列 | old,new;... |
| reorder | 调整列序 | -f, -e 移到末尾 |
| put | 计算新列/修改 | DSL 表达式 |
| filter | 行过滤 | DSL 条件表达式 |
| sort | 排序 | -f, -r 降序, -n 自然序 |
| stats1 | 分组聚合 | -a 聚合函数, -f 字段, -g 分组键 |
| stats2 | 两两列统计 | 相关性等 |
| join | 连接 | -j 键, -l/-r 左/右文件 |
| reshape | 宽长互转 | -r 正则, -s 源字段 |
| uniq | 去重 | -g 分组键, -c 计数 |
| sample | 采样 | -k 固定数, -p 概率 |
| head / tail | 头/尾行 | -n 行数 |
| count | 计数 | 同 wc -l 但识别格式 |
| template | 模板输出 | 自定义格式 |
DSL 表达式速查
# 变量引用
$field_name # 当前记录字段
$* # 所有字段 (迭代用)
# 运算符
+ - * / // % # 算术 (// 整除)
== != < > <= >= # 比较
=~ !~ # 正则匹配/不匹配
&& \|\| ! # 逻辑
. # 字符串拼接
? : # 三元条件
# 内置函数
now() # 当前时间戳
strptime(s, fmt) # 解析时间
strftime(ts, fmt) # 格式化时间
gsub(s, pat, repl) # 全局替换
regex_replace(s, pat, repl) # 正则替换 (支持捕获组)
split(s, sep) # 分割字符串
join(arr, sep) # 数组连接
length(s/arr) # 长度
is_present(v) # 非空检查
is_null(v) # 空检查
abs(x) # 绝对值
sqrt(x) # 平方根
log(x) # 自然对数
exp(x) # 指数
floor/ceil/round # 取整
安装方式
# macOS (Homebrew)
brew install miller
# Linux (包管理器)
apt install miller # Debian/Ubuntu
dnf install miller # Fedora/RHEL
pacman -S miller # Arch
apk add miller # Alpine
# 二进制下载 (GitHub Releases)
# 单文件,无依赖,解压即用
# Docker
docker run --rm -v "${PWD}":/data johnkerl/miller mlr --csv cat data.csv
性能特性
| 特性 | 说明 | |------|------| | 流式处理 | 常数内存 (O(1)),不读全文件 | | 并行度 | 单线程,但 I/O 与计算重叠 | | 格式支持 | CSV/TSV/JSON/JSONL/DKVP/PPrint/XTAB | | 压缩支持 | 透明读写 .gz/.bz2/.zst (自动检测) | | 大文件 | 100GB+ 测试通过 |
故障排查
| 问题 | 解决方案 |
|------|----------|
| "command not found: mlr" | brew install miller 或下载二进制 |
| 字段名有空格/特殊字符 | 用反引号: $'first name' 或 $["first name"] |
| JSON 输入非数组 | 用 --jsonl 逐行处理,或 mlr --json --jsonl cat 转换 |
| 内存仍高 | 检查是否用了 sort/join/stats1 (需物化),改用流式动词 |
| 日期解析失败 | 确认格式字符串匹配,用 strptime 严格模式 |
| 正则不生效 | Miller 正则用 RE2 语法,非 PCRE,避免前瞻/后顾 |
相关技能
- xsv - 索引加速 CSV 统计/切片/连接 (随机访问快)
- visidata - 交互式电子表格 (可视化探索)
- dasel - 统一选择器跨格式查询
- yq - YAML/JSON/XML/CSV 互转与更新
- sqlite-utils - 复杂 SQL 查询 (导入 SQLite 后)
- gron - JSON 扁平化 (配合 mlr 处理嵌套)
- rq - 10+ 格式专用转换器
技能版本: 1.0.0 | 作者: asdw741111 | 适用平台: OpenCode, Claude Code, Cursor, Codex CLI, Windsurf, Gemini CLI
微信扫一扫