A TUI pager with advanced support for tabular data, inferring/swapping delimiters, and real-time event parsing.
See the codeexcel for your logs — pipe in **anything**, wrangle it into columns.
Documentation · Tutorials · Keybindings · Install
nless is a TUI pager for exploring and analyzing tabular data with vi-like keybindings, built on Textual. Pipe in anything and nless infers the structure so you can filter, sort, pivot, and reshape without config. Works with CSV, TSV, JSON, logs, and any delimited output.
pipx install nothing-less
or
brew install mpryor/tap/nless
Requires Python 3.13+ for pipx/pip installs. You can also use pip install nothing-less if you prefer. The Homebrew formula manages its own Python dependency.
kubectl get events -w | nless # stream K8s events
cat access.log | nless # explore log files
nless data.csv # open CSV directly
nless < output.json # redirect a file
Press ? inside nless to view all keybindings.
I frequently need to explore streaming tabular data: server logs, kubectl output, CSV exports, CI pipelines. None of the existing tools had exactly the feature set I wanted, so I built nless.
D, or use regex with named capture groups.Q to pipe and exit, or --no-tui for batch mode.D.d.f/F), exclude (e/E), across all columns (|), or from a search (&).s./), search by cell value (*), navigate matches (n/p).U, focused summary view, dive into grouped data with enter.C), reorder columns (</>).J.!.t.W), copy cell values (y).T._arrival column with A.@ (e.g. 5m, 1h). Append + for rolling windows. Prefix with a column name to filter by parsed timestamps (e.g. timestamp 5m).@colname -> target (epoch, iso, relative, strftime, with optional timezone conversion). Also available from the CLI with --format-timestamp / -F for batch pipelines.--raw or auto-detected. A fast virtual-rendering pager for unstructured text, handling million-line files without columnar overhead.~, with chained accumulation across buffers.Q to pipe and exit, batch mode with --no-tui, or --tui to force interactive mode._source column using --merge.Buffers:
[1-9] - select the buffer at the corresponding indexL - select the next bufferH - select the previous bufferq - close the current active buffer, or the program if all buffers are closedQ - pipe current buffer to stdout and exit immediately (pipe mode shortcut)N - create a new buffer from the original datar - rename the current bufferM - merge the current buffer with another bufferGroups:
} - switch to the next buffer group{ - switch to the previous buffer groupR - rename the current groupO - open a file in a new buffer groupNavigation:
h - move cursor leftl - move cursor rightj - move cursor downk - move cursor up0 - jump to first column$ - jump to final columng - jump to first rowG - jump to final roww - move cursor rightb/B - move cursor leftctrl+u - page upctrl+d - page downc - select a column to jump the cursor toColumn visibility:
C - prompt for a regex filter to selectively display columns, or all to see all columnsm - pin or unpin the current column to the left side of the screen> - move the current column one to the right< - move the current column one to the leftA - toggle the _arrival metadata column showing when each row was receivedPivoting:
U - mark the selected column as part of a composite key to group records by, adding a count column pinned to the leftenter - while over a composite key column, dive into the data behind the pivotFiltering:
f - filter the current column and prompt for a filterF - filter the current column by the highlighted celle - exclude from the current column and prompt for a valueE - exclude the current column by the highlighted cell| - filter ALL columns and prompt for a filter& - apply the current search as a filter across all columns@ - set a time window to show only recent rows (e.g. 5m, 1h); append + for rolling; prefix with column name for column-based filtering (e.g. timestamp 5m); use -> for format conversion (e.g. timestamp -> relative)Searching & Highlighting:
/ - prompt for a search value and jump to the first match* - search all columns for the current highlighted cell valuen - jump to the next matchp - jump to previous match+ - pin the current search as a persistent highlight- - navigate or manage pinned highlightsOutput:
W - prompt for a file to write the current buffer to (- writes to stdout)y - copy the contents of the currently highlighted cell to the clipboardShell Commands:
! - run a shell command and pipe its output into a new bufferTail Mode:
t - toggle tail modex - reset new-line highlightsSessions & Views:
S - open the session menu (save, load, rename, delete)v - open the view menu (save, load, rename, delete)Themes & Keymaps:
T - open the theme selectorK - open the keymap selectorExcluded Lines:
~ - view excluded lines (parse failures + filtered rows), with chained accumulationSorting & Aggregations:
s - toggle ascending/descending sort on the current columna - show column aggregations (count, distinct, sum, avg, min, max)JSON:
J - select a JSON field under the current cell to add as a columnDelimiter/file parsing:
D - swap the delimiter on the fly (common delimiters, regex with named capture groups, raw, json, or for double-space aligned output like kubectl)d - split a column into more columns using a columnar delimiter (json, regex with named capture groups, or any string)P - auto-detect a known log format and apply it as a regex delimiterHelp:
? - show the help screen with all keybindingsMouse:
See the full keybinding reference and tutorials for more.
Contributions are welcome! See the contributing guidelines for details.
If nless doesn't have what you need, check out these other great tools:
| nless | VisiData | csvlens | lnav | Toolong | |
|---|---|---|---|---|---|
| Focus | Tabular data pager | Data multitool | CSV viewer | Log navigator | Log viewer |
| Language | Python | Python | Rust | C++ | Python |
| Streaming / stdin | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :white_check_mark: | :white_check_mark: |
| Delimiter inference | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :x: | :x: |
| Vi keybindings | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Filtering | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :white_check_mark: | :x: |
| Sorting | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :x: |
| Pivoting / grouping | :white_check_mark: | :white_check_mark: | :x: | :heavy_minus_sign: | :x: |
| JSON parsing | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :heavy_minus_sign: |
| Log format detection | :white_check_mark: | :x: | :x: | :white_check_mark: | :heavy_minus_sign: |
| Regex column parsing | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: |
| Pipe mode | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :x: |
| Raw text pager | :white_check_mark: | :heavy_minus_sign: | :x: | :white_check_mark: | :white_check_mark: |
| Themes | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :white_check_mark: | :x: |
| SQL queries | :x: | :x: | :x: | :white_check_mark: | :x: |
| Python expressions | :x: | :white_check_mark: | :x: | :x: | :x: |
| Timestamp parsing | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: |
| Multi-file merge | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: |
:white_check_mark: full support · :heavy_minus_sign: partial · :x: not supported
Python
98.8%
Shell
1.2%
A TUI pager with advanced support for tabular data, inferring/swapping delimiters, and real-time event parsing.
See the codeexcel for your logs — pipe in **anything**, wrangle it into columns.
Documentation · Tutorials · Keybindings · Install
nless is a TUI pager for exploring and analyzing tabular data with vi-like keybindings, built on Textual. Pipe in anything and nless infers the structure so you can filter, sort, pivot, and reshape without config. Works with CSV, TSV, JSON, logs, and any delimited output.
pipx install nothing-less
or
brew install mpryor/tap/nless
Requires Python 3.13+ for pipx/pip installs. You can also use pip install nothing-less if you prefer. The Homebrew formula manages its own Python dependency.
kubectl get events -w | nless # stream K8s events
cat access.log | nless # explore log files
nless data.csv # open CSV directly
nless < output.json # redirect a file
Press ? inside nless to view all keybindings.
I frequently need to explore streaming tabular data: server logs, kubectl output, CSV exports, CI pipelines. None of the existing tools had exactly the feature set I wanted, so I built nless.
D, or use regex with named capture groups.Q to pipe and exit, or --no-tui for batch mode.D.d.f/F), exclude (e/E), across all columns (|), or from a search (&).s./), search by cell value (*), navigate matches (n/p).U, focused summary view, dive into grouped data with enter.C), reorder columns (</>).J.!.t.W), copy cell values (y).T._arrival column with A.@ (e.g. 5m, 1h). Append + for rolling windows. Prefix with a column name to filter by parsed timestamps (e.g. timestamp 5m).@colname -> target (epoch, iso, relative, strftime, with optional timezone conversion). Also available from the CLI with --format-timestamp / -F for batch pipelines.--raw or auto-detected. A fast virtual-rendering pager for unstructured text, handling million-line files without columnar overhead.~, with chained accumulation across buffers.Q to pipe and exit, batch mode with --no-tui, or --tui to force interactive mode._source column using --merge.Buffers:
[1-9] - select the buffer at the corresponding indexL - select the next bufferH - select the previous bufferq - close the current active buffer, or the program if all buffers are closedQ - pipe current buffer to stdout and exit immediately (pipe mode shortcut)N - create a new buffer from the original datar - rename the current bufferM - merge the current buffer with another bufferGroups:
} - switch to the next buffer group{ - switch to the previous buffer groupR - rename the current groupO - open a file in a new buffer groupNavigation:
h - move cursor leftl - move cursor rightj - move cursor downk - move cursor up0 - jump to first column$ - jump to final columng - jump to first rowG - jump to final roww - move cursor rightb/B - move cursor leftctrl+u - page upctrl+d - page downc - select a column to jump the cursor toColumn visibility:
C - prompt for a regex filter to selectively display columns, or all to see all columnsm - pin or unpin the current column to the left side of the screen> - move the current column one to the right< - move the current column one to the leftA - toggle the _arrival metadata column showing when each row was receivedPivoting:
U - mark the selected column as part of a composite key to group records by, adding a count column pinned to the leftenter - while over a composite key column, dive into the data behind the pivotFiltering:
f - filter the current column and prompt for a filterF - filter the current column by the highlighted celle - exclude from the current column and prompt for a valueE - exclude the current column by the highlighted cell| - filter ALL columns and prompt for a filter& - apply the current search as a filter across all columns@ - set a time window to show only recent rows (e.g. 5m, 1h); append + for rolling; prefix with column name for column-based filtering (e.g. timestamp 5m); use -> for format conversion (e.g. timestamp -> relative)Searching & Highlighting:
/ - prompt for a search value and jump to the first match* - search all columns for the current highlighted cell valuen - jump to the next matchp - jump to previous match+ - pin the current search as a persistent highlight- - navigate or manage pinned highlightsOutput:
W - prompt for a file to write the current buffer to (- writes to stdout)y - copy the contents of the currently highlighted cell to the clipboardShell Commands:
! - run a shell command and pipe its output into a new bufferTail Mode:
t - toggle tail modex - reset new-line highlightsSessions & Views:
S - open the session menu (save, load, rename, delete)v - open the view menu (save, load, rename, delete)Themes & Keymaps:
T - open the theme selectorK - open the keymap selectorExcluded Lines:
~ - view excluded lines (parse failures + filtered rows), with chained accumulationSorting & Aggregations:
s - toggle ascending/descending sort on the current columna - show column aggregations (count, distinct, sum, avg, min, max)JSON:
J - select a JSON field under the current cell to add as a columnDelimiter/file parsing:
D - swap the delimiter on the fly (common delimiters, regex with named capture groups, raw, json, or for double-space aligned output like kubectl)d - split a column into more columns using a columnar delimiter (json, regex with named capture groups, or any string)P - auto-detect a known log format and apply it as a regex delimiterHelp:
? - show the help screen with all keybindingsMouse:
See the full keybinding reference and tutorials for more.
Contributions are welcome! See the contributing guidelines for details.
If nless doesn't have what you need, check out these other great tools:
| nless | VisiData | csvlens | lnav | Toolong | |
|---|---|---|---|---|---|
| Focus | Tabular data pager | Data multitool | CSV viewer | Log navigator | Log viewer |
| Language | Python | Python | Rust | C++ | Python |
| Streaming / stdin | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :white_check_mark: | :white_check_mark: |
| Delimiter inference | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :x: | :x: |
| Vi keybindings | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| Filtering | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :white_check_mark: | :x: |
| Sorting | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :x: |
| Pivoting / grouping | :white_check_mark: | :white_check_mark: | :x: | :heavy_minus_sign: | :x: |
| JSON parsing | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :heavy_minus_sign: |
| Log format detection | :white_check_mark: | :x: | :x: | :white_check_mark: | :heavy_minus_sign: |
| Regex column parsing | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: |
| Pipe mode | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :heavy_minus_sign: | :x: |
| Raw text pager | :white_check_mark: | :heavy_minus_sign: | :x: | :white_check_mark: | :white_check_mark: |
| Themes | :white_check_mark: | :white_check_mark: | :heavy_minus_sign: | :white_check_mark: | :x: |
| SQL queries | :x: | :x: | :x: | :white_check_mark: | :x: |
| Python expressions | :x: | :white_check_mark: | :x: | :x: | :x: |
| Timestamp parsing | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: |
| Multi-file merge | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: |
:white_check_mark: full support · :heavy_minus_sign: partial · :x: not supported
Python
98.8%
Shell
1.2%