README.md (8031B)
1 <div align="center"> 2 3 <h1>xl-cli-tools</h1> 4 <h3>View, edit, query, and diff Excel files from the command line</h3> 5 6 [](https://claude.ai) 7 [](LICENSE) 8 9 <table> 10 <tr> 11 <td align="center" width="50%"><strong>xlcat</strong> — view</td> 12 <td align="center" width="50%"><strong>xlset</strong> — edit</td> 13 </tr> 14 <tr> 15 <td><img src="demo/xlcat.gif" alt="xlcat demo" /></td> 16 <td><img src="demo/xlset.gif" alt="xlset demo" /></td> 17 </tr> 18 <tr> 19 <td align="center" width="50%"><strong>xlfilter</strong> — query</td> 20 <td align="center" width="50%"><strong>xldiff</strong> — compare</td> 21 </tr> 22 <tr> 23 <td><img src="demo/xlfilter.gif" alt="xlfilter demo" /></td> 24 <td><img src="demo/xldiff.gif" alt="xldiff demo" /></td> 25 </tr> 26 </table> 27 28 </div> 29 30 *** 31 32 [**xlcat**](#xlcat--view-excel-files) · [**xlset**](#xlset--edit-excel-cells) · [**xlfilter**](#xlfilter--query-and-filter) · [**xldiff**](#xldiff--compare-two-sheets) · [**Install**](#installation) · [**Claude Code**](#claude-code-integration) 33 34 *** 35 36 Four binaries, no runtime dependencies: 37 38 ```bash 39 # View a spreadsheet 40 xlcat report.xlsx 41 42 # Edit a cell 43 xlset report.xlsx B3=42 44 45 # Filter rows 46 xlfilter data.xlsx --where "Amount>1000" --sort "Amount:desc" 47 48 # Diff two files 49 xldiff old.xlsx new.xlsx --key ID 50 ``` 51 52 ## Installation 53 54 ### Pre-built binaries (macOS) 55 56 Download from [Releases](https://github.com/LouLouLibs/xl-cli-tools/releases): 57 58 ```bash 59 # Apple Silicon (macOS) 60 for tool in xlcat xlset xlfilter xldiff; do 61 curl -L "https://github.com/LouLouLibs/xl-cli-tools/releases/latest/download/${tool}-aarch64-apple-darwin" \ 62 -o ~/.local/bin/$tool 63 done 64 chmod +x ~/.local/bin/xl{cat,set,filter,diff} 65 66 # Linux (x86_64) 67 for tool in xlcat xlset xlfilter xldiff; do 68 curl -L "https://github.com/LouLouLibs/xl-cli-tools/releases/latest/download/${tool}-x86_64-linux" \ 69 -o ~/.local/bin/$tool 70 done 71 chmod +x ~/.local/bin/xl{cat,set,filter,diff} 72 ``` 73 74 ### From source 75 76 ```bash 77 cargo install --path . 78 ``` 79 80 Requires Rust 1.85+. 81 82 ## xlcat — View Excel Files 83 84 ```bash 85 # Overview: metadata, schema, first/last 25 rows 86 xlcat report.xlsx 87 88 # Column names and types only 89 xlcat report.xlsx --schema 90 91 # Summary statistics (count, mean, std, min, max, median) 92 xlcat report.xlsx --describe 93 94 # Pick a sheet in a multi-sheet workbook 95 xlcat report.xlsx --sheet Revenue 96 97 # First 10 rows / last 5 rows / both 98 xlcat report.xlsx --head 10 99 xlcat report.xlsx --tail 5 100 xlcat report.xlsx --head 10 --tail 5 101 102 # All rows (overrides large-file gate) 103 xlcat report.xlsx --all 104 105 # CSV output for piping 106 xlcat report.xlsx --csv 107 xlcat report.xlsx --csv --head 100 > subset.csv 108 ``` 109 110 ### Example output 111 112 ``` 113 # File: sales.xlsx (245 KB) 114 # Sheets: 1 115 116 ## Sheet: Q1 (1240 rows x 4 cols) 117 118 | Column | Type | 119 |---------|--------| 120 | date | Date | 121 | region | String | 122 | amount | Float | 123 | units | Int | 124 125 | date | region | amount | units | 126 |------------|--------|---------|-------| 127 | 2024-01-01 | East | 1234.56 | 100 | 128 | 2024-01-02 | West | 987.00 | 75 | 129 ... (1190 rows omitted) ... 130 | 2024-12-30 | East | 1100.00 | 92 | 131 | 2024-12-31 | West | 1250.75 | 110 | 132 ``` 133 134 ### Adaptive defaults 135 136 - **Single sheet, <=50 rows:** shows all data 137 - **Single sheet, >50 rows:** first 25 + last 25 rows 138 - **Multiple sheets:** lists schemas, pick one with `--sheet` 139 - **Large file (>1MB):** schema + first 25 rows (override with `--max-size 5M`) 140 141 ## xlset — Edit Excel Cells 142 143 ```bash 144 # Set a single cell 145 xlset report.xlsx A2=42 146 147 # Set multiple cells 148 xlset report.xlsx A2=42 B2="hello world" C2=true 149 150 # Preserve leading zeros with type tag 151 xlset report.xlsx A2:str=07401 152 153 # Target a specific sheet 154 xlset report.xlsx --sheet Revenue A2=42 155 156 # Write to a new file (don't modify original) 157 xlset report.xlsx --output modified.xlsx A2=42 158 159 # Bulk update from CSV 160 xlset report.xlsx --from updates.csv 161 162 # Bulk from stdin 163 echo "A1,42" | xlset report.xlsx --from - 164 ``` 165 166 ### Type inference 167 168 Values are auto-detected: `42` becomes a number, `true` becomes boolean, `2024-01-15` becomes a date. Override with tags when needed: 169 170 | Tag | Effect | 171 |-----|--------| 172 | `:str` | Force string (`A1:str=07401` preserves leading zero) | 173 | `:num` | Force number | 174 | `:bool` | Force boolean | 175 | `:date` | Force date | 176 177 ### CSV format for `--from` 178 179 ```csv 180 cell,value 181 A1,42 182 B2,hello world 183 C3:str,07401 184 D4,"value with, comma" 185 ``` 186 187 ### What gets preserved 188 189 xlset modifies only the cells you specify. Everything else is untouched: formatting, formulas, charts, conditional formatting, data validation, merged cells, images. 190 191 ## xlfilter — Query and Filter 192 193 ```bash 194 # Filter rows by value 195 xlfilter data.xlsx --where "State=CA" 196 197 # Numeric comparisons 198 xlfilter data.xlsx --where "Amount>1000" 199 200 # Multiple filters (AND) 201 xlfilter data.xlsx --where "State=CA" --where "Amount>1000" 202 203 # Select columns (by name or letter) 204 xlfilter data.xlsx --cols State,Amount,Year 205 xlfilter data.xlsx --cols A,C,D 206 207 # Sort results 208 xlfilter data.xlsx --sort "Amount:desc" 209 210 # Limit output 211 xlfilter data.xlsx --sort "Amount:desc" --limit 10 212 213 # Contains filter (case-insensitive) 214 xlfilter data.xlsx --where "Name~john" 215 216 # Skip metadata rows above the real header 217 xlfilter data.xlsx --skip 2 218 219 # CSV output for piping 220 xlfilter data.xlsx --where "Status!=Draft" --csv | other-tool 221 222 # Target a specific sheet 223 xlfilter data.xlsx --sheet Revenue --where "Amount>5000" 224 ``` 225 226 ### Filter operators 227 228 | Operator | Meaning | Example | 229 |----------|---------|---------| 230 | `=` | Equals | `State=CA` | 231 | `!=` | Not equals | `Status!=Draft` | 232 | `>` | Greater than | `Amount>1000` | 233 | `<` | Less than | `Year<2024` | 234 | `>=` | Greater or equal | `Score>=90` | 235 | `<=` | Less or equal | `Price<=50` | 236 | `~` | Contains (case-insensitive) | `Name~john` | 237 | `!~` | Not contains | `Name!~test` | 238 239 Numeric columns compare numerically; string columns compare lexicographically. Row count is printed to stderr. 240 241 ## xldiff — Compare Two Sheets 242 243 ```bash 244 # Positional diff (whole-row comparison) 245 xldiff old.xlsx new.xlsx 246 247 # Key-based diff (match rows by ID, compare cell by cell) 248 xldiff old.xlsx new.xlsx --key ID 249 250 # Composite key 251 xldiff old.xlsx new.xlsx --key Date,Ticker 252 253 # Compare sheets within the same file 254 xldiff report.xlsx:Q1 report.xlsx:Q2 255 256 # Float tolerance (differences <= 0.01 treated as equal) 257 xldiff old.xlsx new.xlsx --key ID --tolerance 0.01 258 259 # Only compare specific columns 260 xldiff old.xlsx new.xlsx --key ID --cols Name,Salary 261 262 # Skip metadata rows (different skip per file) 263 xldiff file1.xlsx file2.xlsx --skip 3,5 264 265 # Output formats 266 xldiff old.xlsx new.xlsx --key ID --format markdown 267 xldiff old.xlsx new.xlsx --key ID --format json 268 xldiff old.xlsx new.xlsx --key ID --format csv 269 ``` 270 271 ### Example output 272 273 ``` 274 --- Sheet1 (old.xlsx) 275 +++ Sheet1 (new.xlsx) 276 277 Added: 1 | Removed: 1 | Modified: 2 278 279 - ID: "3" Name: "Charlie" Department: "Engineering" Salary: "88000" 280 + ID: "5" Name: "Eve" Department: "Marketing" Salary: "70000" 281 ~ ID: "1" 282 Salary: "95000" → "98000" 283 ~ ID: "2" 284 Department: "Marketing" → "Design" 285 Salary: "72000" → "75000" 286 ``` 287 288 ### Diff modes 289 290 **Positional (no `--key`):** Every column defines row identity. Reports added/removed rows only. 291 292 **Key-based (`--key`):** Match rows by key columns, compare remaining columns cell by cell. Reports added, removed, and modified rows with per-cell changes. Supports composite keys, duplicate key detection, and float tolerance. 293 294 ### Exit codes (diff convention) 295 296 | Code | Meaning | 297 |------|---------| 298 | 0 | No differences | 299 | 1 | Differences found | 300 | 2 | Error | 301 302 ## Claude Code integration 303 304 Claude Code skills are available in [claude-skills](https://github.com/LouLouLibs/claude-skills). Claude can view spreadsheets, analyze data, filter rows, compare files, and make targeted edits in conversations. 305 306 ## Exit codes 307 308 | Code | Meaning | 309 |------|---------| 310 | 0 | Success | 311 | 1 | Runtime error (xldiff: differences found) | 312 | 2 | Invalid arguments | 313 314 ## License 315 316 MIT