Home / Alt manpages / lesspipe(1)

  • lesspipe(1)
  • User command
  • linux

View Compressed Files in less with lesspipe

Open a gzipped log directly in less without decompressing it first, and lesspipe is the script making that possible. It works quietly on most distributions. You will turn on streaming conversion, compare it against the temporary-file behaviour of its lessfile alias, and know when each one is the better choice. The examples match the installed Debian script from package less version 590-2ubuntu2.1.

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. None of the examples alter the files being inspected.

1. Check the installed command

Confirm which script your shell will actually 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
  • lessfile is a symlink to lesspipe on this installation. The script changes behaviour based on the name it was invoked as.
  • lesspipe streams converted text straight to standard output.
  • lessfile writes to a private temporary file, which gives less normal percentage positions and deletes the file again when it closes.

Checkpoint

If either helper is missing, stop and install the distribution's less package through your normal package manager. 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 marks this as an input pipe. When less opens a recognised file, the helper writes the replacement text to standard output, and less can start reading before conversion has even finished. A streamed file is positioned by bytes rather than a ready percentage, so jumping to the end can force the conversion to complete first.

For a persistent setup, put the same line 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, until you understand that shell's startup rules.

Checkpoint

Open a compressed file with less /path/to/file.gz and press q to leave. You should see decompressed text, not gzip bytes.

3. Try a safe compressed-file example

Create a small test file in a working directory for a reproducible check. The redirection below 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. To test the converter without opening the pager at all, run it directly:

$ lesspipe /tmp/lesspipe-example.txt.gz
first line
second line

That is the same stream the configured input pipe hands to less, useful for diagnosis on its own. The helper recognises extensions, so a file with compressed content but an unrelated name may not get converted at all.

Safety boundary

Viewing an archive can invoke external tools such as tar, unzip, pdftotext or ImageMagick's identify. Treat an untrusted archive or document as input to a whole collection of parsers, not a single trusted step. 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 right from 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 anything, then reads the temporary replacement file. The script creates it with a restrictive umask and removes it through LESSCLOSE once you leave less. It starts slower, but percentage positions are there from the first screen.

Do not configure both modes in the same startup file. The last eval wins, so a later line can silently replace the helper you meant to keep.

Recovery

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 too if you made it persistent. The temporary test files can go later with rm -- /tmp/lesspipe-example.txt /tmp/lesspipe-example.txt.gz; that deletion is irreversible, so check the paths before you run it.

5. Add a user-defined filter only when needed

The installed script checks $XDG_CONFIG_HOME/lessfilter first, then ~/.lessfilter. It must be executable, and its exit status is the whole contract: 0 means it handled the file, 1 means the standard helper should carry on. 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, an ordinary user-level change. Test it directly before opening less at all:

$ ~/.lessfilter /path/to/example.log.json
$ printf 'filter status: %s\n' "$?"
filter status: 0

Warning

Return status 1 for every extension you do not own. A filter that prints a diagnostic but returns 0 is claiming to have handled the input, so the built-in decompression or archive logic never gets a chance. Remove the filter, or restore its previous contents, if it starts changing how unrelated files open.

6. Diagnose unexpected output

If less shows shell-startup text before the file, the helper is being run inside a shell, and that shell may read $BASH_ENV. A non-interactive startup file that prints a banner can 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 stray echo commands out of non-interactive startup files, or guard Bash-only output so it only fires for an interactive shell:

if [ -z "$PS1" ]; then
    return 0 2>/dev/null || exit 0
fi

Use that guard only in a file that is genuinely safe to return or exit from, and test it in a separate terminal before relying on it for automation.

Tip

If a format prints "No ... available", the helper recognised the extension but the supporting program is missing. 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

  • Right binaries confirmed: lesspipe and lessfile resolve to the intended installed script.
  • Mode chosen deliberately: streaming percentages or the temporary-file mode, picked on purpose.
  • Test file proved it works: a compressed file opens as text and the original stays unchanged.
  • Custom filter is safe: executable, returns 0 only for formats it actually handles, with a clear fallback.
  • Failure modes told apart: shell startup noise and a missing decoder tool are not the same problem.