Quote Metacharacters Reliably with lessecho

lessecho is the quiet helper less uses internally to escape file names, and you can drive it directly from a script. Do that when you need a predictable escaped argument instead of shell guesswork. This walks through marking exactly the characters you choose as metacharacters, changing the escape character, and switching to quote mode. Allow about ten minutes. You need the less package and an ordinary shell; none of the examples need elevated privileges.

This guide matches the installed version here: less package 590-2ubuntu2.1, manual page labelled Version 590 from 3 June 2021. Other releases may differ, so check your local manual before putting an option into a long-lived script.

1. Check the installed command

Start with read-only checks. They identify the executable and confirm the package version without touching any files or shell settings:

$ command -v lessecho
/usr/bin/lessecho
$ lessecho --version
1.15
$ dpkg-query -W -f='${Package} ${Version}\n' less
less 590-2ubuntu2.1

The version numbers look unrelated because the command reports its own small version while the package records the distribution build. The manual is the contract for what each option means. The program writes its arguments to standard output, separated by spaces, and returns a non-zero status for an invalid option.

Checkpoint: if command -v points somewhere unexpected, stop and inspect your PATH. Do not assume a similarly named wrapper behaves the same way.

2. See the default output

With no metacharacters configured, lessecho simply prints the arguments back. The shell still handles quoting before the program ever sees them, so quote a file name with spaces at the call site:

$ lessecho 'report one.txt' 'src/main.c'
report one.txt src/main.c
$ printf 'exit status: %s\n' "$?"
exit status: 0

3. Mark a character as a metacharacter

Use -mx to make the character x a metacharacter. -m: marks a colon, and the default escape character is a backslash:

$ lessecho -m: 'report:one.txt' 'plain.txt'
report\:one.txt plain.txt
$ printf 'exit status: %s\n' "$?"
exit status: 0

Only the colon is escaped here. The full stop and the space are untouched because they were never configured as metacharacters. The option does not enable globbing, inspect the filesystem or modify input; it only changes the bytes written to standard output.

For a character given by its numeric value, use -nn. Decimal 58 is the character code for a colon on the installed command:

$ lessecho -n58 'report:one.txt'
report\:one.txt

Tip: use the numeric form when a script needs the character choice to be unambiguous, and keep the value next to a comment or variable naming the intended character. Otherwise it is easy to mistake it for an unrelated option value.

4. Change the escape character

Use -ex to choose the escape character. This example uses a caret:

$ lessecho -m: -e^ 'report:one.txt'
report^:one.txt

The argument to -e is exactly one character. Shell syntax that hands the program more than one character will not mean what you intended. Check the actual bytes with a byte-oriented tool when the distinction matters:

$ output=$(lessecho -m: -e^ 'report:one.txt')
$ printf '%s\n' "$output"
report^:one.txt
$ printf '%s' "$output" | od -An -t x1
 72 65 70 6f 72 74 5e 3a 6f 6e 65 2e 74 78 74

Command substitution strips trailing newlines, harmless here but not always harmless in a different pipeline. Prefer a direct redirection or pipe when preserving the exact stream matters.

5. Use quote mode when no escape character is wanted

Set the escape character to a hyphen with -e-. In this mode the manual says arguments containing metacharacters get wrapped in the configured quote characters instead of receiving an escape character:

$ lessecho -m: -e- 'report:one.txt' 'plain.txt'
"report:one.txt" plain.txt

The default opening and closing quote characters are double quotes. Change them with -ox and -cx if the consumer expects a different pair. These options change the representation; they do not make the result universally safe for a particular shell or parser. Confirm the receiving program's quoting rules before wiring the output into an evaluation step.

Safety boundary: do not pass lessecho output to eval, a shell command string, or another interpreter just because it contains backslashes or quotes. Keep arguments separate where possible, and treat the output as data until you have established the consumer's grammar.

6. Quote every argument deliberately

Use -a when every argument should be quoted, not just ones containing configured metacharacters:

$ lessecho -m: -a 'plain.txt' 'report:one.txt'
"plain.txt" "report:one.txt"
$ printf 'exit status: %s\n' "$?"
exit status: 0

This is a formatting choice, not a file operation. It does not create files, alter names or check whether they exist, and it does not recursively quote anything inside an argument. If an argument itself contains a quote character, pick quote characters and an escape policy the downstream consumer explicitly supports.

7. Diagnose an option or pipeline failure

An unknown option is rejected outright. Capture the status immediately if a script must distinguish a failed formatter from an empty result:

$ lessecho -z
Invalid option letter
$ status=$?
$ printf 'lessecho status: %s\n' "$status"
lessecho status: 1

Do not treat blank-looking output as proof that no arguments were supplied. Check the arguments at the call site and preserve the exit status before running anything else. For a pipeline, turn on the shell's pipeline failure handling, or inspect each process's status individually.

The option names stay compact throughout the manual: -m and -n add metacharacters, -e changes the escape character, -o and -c set quote delimiters, -p and -d set those delimiters by integer value, and -f sets the escape character by integer value. Reach for those numeric forms only when a consuming interface requires them, and verify with a small literal input before trusting them in automation.

Done means