Make less Read Archives and Compressed Files with lesspipe
You will configure less to inspect compressed files, archive listings and other recognised formats through lesspipe, then choose when the temporary-file behaviour of its lessfile alias is more useful. The examples match the installed Debian script from package less version 590-2ubuntu2.1.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes. You need less, a POSIX shell and a writable home directory. The setup is an ordinary per-user change, so it does not need sudo. The examples do not alter the files being inspected.
1. Check the installed command
Confirm which script your shell will call and record the package version. This catches the common mistake of reading documentation for one installation while running another:
$ command -v less lesspipe lessfile
/usr/bin/less
/usr/bin/lesspipe
/usr/bin/lessfile
$ dpkg-query -W -f='${Package} ${Version}\n' less
less 590-2ubuntu2.1
On this installation, lessfile is a symbolic link to lesspipe. The script changes its behaviour according to the name used to invoke it. lesspipe streams converted text to standard output. lessfile writes converted text to a private temporary file, which gives less normal percentage positions and removes the temporary file when it closes it.
Checkpoint
If either helper is missing, stop here and install the distribution's less package through your normal package-management process. Do not copy a script from an unrelated host into /usr/bin.
2. Enable streaming conversion with lesspipe
Ask the helper to print shell assignments, then evaluate that output in your current shell:
$ eval "$(lesspipe)"
$ printf 'LESSOPEN=%s\nLESSCLOSE=%s\n' "$LESSOPEN" "$LESSCLOSE"
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
The leading vertical bar in LESSOPEN means this is an input pipe. When less opens a recognised file, the helper writes the replacement text to its standard output and less can start reading before the whole conversion has finished. A streamed file is positioned by bytes rather than a ready percentage; jumping to the end can require the conversion to finish.
For a persistent setup, put the same command in the interactive shell startup file you actually use, such as ~/.bashrc for interactive Bash sessions. Do not put it in a script that must produce machine-readable output without first understanding that shell's startup rules.
Checkpoint
Open a compressed file with less /path/to/file.gz. Press q to leave. The displayed content should be decompressed text, not gzip bytes.
3. Try a safe compressed-file example
Create a small test file in a working directory if you want a reproducible check. The redirection writes only the named test files:
$ printf 'first line\nsecond line\n' > /tmp/lesspipe-example.txt
$ gzip -c /tmp/lesspipe-example.txt > /tmp/lesspipe-example.txt.gz
$ less /tmp/lesspipe-example.txt.gz
Inside less, search for second with /second, then press q. If you want to test the converter without opening the pager, run:
$ lesspipe /tmp/lesspipe-example.txt.gz
first line
second line
That direct command is useful for diagnosis. Its output is the same stream that the configured input pipe gives to less. The helper recognises extensions, so a file with compressed content but an unrelated name may not be converted.
Safety boundary
Viewing an archive can invoke external tools such as tar, unzip, pdftotext or ImageMagick's identify. Treat untrusted archives and documents as input to a collection of parsers. Do not make a file executable or run a program merely because lesspipe can describe it.
4. Compare lessfile when percentages matter
If you need a conventional percentage position at the start of a long converted file, use the alias instead:
$ eval "$(lessfile)"
$ printf 'LESSOPEN=%s\nLESSCLOSE=%s\n' "$LESSOPEN" "$LESSCLOSE"
LESSOPEN=/usr/bin/lessfile %s
LESSCLOSE=/usr/bin/lessfile %s %s
$ less /tmp/lesspipe-example.txt.gz
This mode finishes the conversion before less displays it, then reads the temporary replacement file. The script creates it with a restrictive umask and removes it through LESSCLOSE after you leave less. It is slower to start, but percentage positions are available up front.
Do not configure both modes in the same startup file. The last eval wins, so a later line can silently replace your preferred helper.
Undo: close the current shell and open a new one, or unset the two variables explicitly:
$ unset LESSOPEN LESSCLOSE
Remove the setup line from your shell startup file if you made it persistent. The temporary test files can be removed later with rm -- /tmp/lesspipe-example.txt /tmp/lesspipe-example.txt.gz; that deletion is irreversible, so check the paths before running it.
5. Add a user-defined filter only when needed
The installed script checks $XDG_CONFIG_HOME/lessfilter first and then ~/.lessfilter. It must be executable. A filter returns status 0 when it handled the file, and status 1 when the standard helper should continue. Keep the fallback branch explicit:
#!/bin/sh
case "$1" in
*.log.json)
jq . -- "$1"
exit 0
;;
*)
exit 1
;;
esac
Save that as ~/.lessfilter only if jq is installed and JSON logs are genuinely part of your workflow. Then make it executable with chmod 700 ~/.lessfilter, which is an ordinary user-level change. Test it directly before opening less:
$ ~/.lessfilter /path/to/example.log.json
$ printf 'filter status: %s\n' "$?"
filter status: 0
Return status 1 for every extension you do not own. A filter that prints a diagnostic but returns 0 claims to have handled the input, so the built-in decompression or archive logic will not get a chance. Remove the filter, or restore its previous contents, if it changes the way unrelated files open.
6. Diagnose unexpected output
If less shows shell-startup text before the file, the helper is being run by a shell and that shell may read $BASH_ENV. A non-interactive startup file that prints a banner can therefore pollute the replacement stream. Inspect the variable without executing its value:
$ printf 'BASH_ENV=%s\n' "${BASH_ENV-}"
$ printf 'SHELL=%s\n' "$SHELL"
$ type -a lesspipe lessfile
Move diagnostic echo commands out of non-interactive startup files, or guard Bash-only output so it runs only for an interactive shell:
if [ -z "$PS1" ]; then
return 0 2>/dev/null || exit 0
fi
Use the guard only in a file that is safe to return from or exit from. Test the shell startup change in a separate terminal before relying on it for automation.
If a format prints "No ... available", the helper recognised the extension but the supporting program is absent. Verify the exact dependency with command -v PROGRAM. Installing a missing decoder is a package-management decision; do not substitute an executable downloaded from an untrusted location.
Done means
lesspipeandlessfileresolve to the intended installed script.- You chose streaming percentages or the temporary-file mode deliberately.
- A compressed test file opens as text, and its original file remains unchanged.
- Any custom filter is executable, returns 0 only for formats it handles, and has a safe fallback.
- Shell startup output and missing decoder tools are recognised as separate failure modes.