Clean Reverse Line Feeds from Terminal Output with col
Pipe nroff output into a file and you get a mess of backspaces and reverse line feeds. col turns that into plain text you can read, save and hand to another command. This guide uses the col from Ubuntu's bsdextrautils package, version 2.39.3 on the machine used for these examples, and it takes about 10 minutes. You need a shell and some input that may contain terminal control characters. No elevated privileges.
The route
Jump straight to the step you need, or tick off Done means at the end.
1. Know what col does
col reads standard input and writes standard output. It filters reverse and half-reverse line feeds so the result only moves forward or half-forward. It is most useful on output from nroff and tbl, where a terminal would normally act on the carriage motion instead of showing clean text.
It also understands backspaces, tabs, carriage returns and a small set of escape sequences. Unknown control characters and escape sequences are discarded by default. That gives readable text, but it makes col a formatter, not a lossless converter of control sequences.
2. Confirm the installed implementation
Check which binary your shell will run, then ask it for its version:
command -v col
col --version
On the reference system the relevant output is:
/usr/bin/col
col from util-linux 2.39.3
Checkpoint
If your path selects another copy, read that installation's manual too. The options here match the local col(1) manual, and the command normally comes from the bsdextrautils package on Ubuntu.
3. Filter a file or pipeline
Pass the noisy input on standard input. Send the result to a new file while you inspect it:
col < terminal-output.txt > cleaned-output.txt
less cleaned-output.txt
In a pipeline, put col after the program that emits terminal formatting:
nroff -man /usr/share/man/man1/col.1.gz | col | less
There is no service to restart and no system state to undo. The redirection creates or replaces only the named output file. If you used the wrong destination, delete that generated file or rerun with another one.
Warning
Do not redirect over the original input until you have inspected the result.
4. See reverse-feed cleanup without a terminal
This test builds a reverse-feed escape sequence with printf, passes it through col, then shows the bytes as hexadecimal so terminal rendering cannot hide the change:
printf 'top\0337bottom\n' | col | od -An -t x1c
The important part of the output is:
74 6f 70 62 6f 74 74 6f 6d 0a
t o p b o t t o m \n
The ESC-7 sequence is carriage motion, not visible text. col removes its terminal effect and emits the characters in a forward-readable order. A vertical tab is another reverse line-feed input that the program understands.
5. Choose how backspaces are handled
A backspace moves one column back. By default col can keep backspaces in its output. Add -b (or --no-backspaces) when the consumer needs one visible character per column and must not receive backspace bytes:
printf 'ab\bX\n' | col -b
# expected visible line: aX
Use -b when preparing plain text for a parser, a diff or a file that should not contain terminal overstriking.
Warning
-b keeps only the last character written at each column position. It is a presentation choice and it can discard earlier characters.
6. Control half-line and whitespace output
Characters meant for a half-line boundary normally move to the following full line. Use -f (or --fine) to permit half-forward line feeds when that positioning matters:
nroff -man /usr/share/man/man1/col.1.gz | col -f | less
Tabs and spaces are separate output decisions:
-hor--tabs. Emits tabs instead of multiple spaces where possible.-xor--spaces. Emits multiple spaces instead of tabs.
Choose -x when literal spacing is clearer or tab width is not under your control. Choose -h when compact tabular output is more useful. The two are not semantically equivalent, so check the resulting file if column alignment matters.
7. Use the less common options with care
-p (or --pass) passes unknown control sequences through unchanged. That is the opposite of the normal filtering behaviour. Use it only when a later stage understands those sequences and you have checked the input source.
Warning
Passing terminal controls into a log, web page or parser can make the output misleading or unsafe to display.
-l number (or --lines number) asks col to buffer at least that many lines. The default is 128. This is an extension beyond the standard interface, and it matters mainly when input moves backwards further than the default buffer. A warning is printed if input tries to back up to the last line already flushed.
Keep number positive and raise it only when you have evidence the input needs more buffering, since a larger value uses more memory. Check the status and stderr rather than assuming a warning was harmless:
col -l 256 < terminal-output.txt > cleaned-output.txt
printf 'col exit status: %s\n' "$?"
Common traps
- Judging by eye in a terminal. Use
odor an editor that shows control characters, so you know whether bytes were removed or merely interpreted. - Expecting every escape sequence to survive. Unrecognised controls are discarded unless you select
-p. - Treating
-hand-xas cosmetic. When another program reads the result, tabs and spaces can produce different fields. - Trusting the pipeline status. In a simple shell pipeline the final status is usually that of
col. Capture or inspect the producer's errors separately when failure matters.
Done means
- Version known.
col --versionidentifies the implementation you tested. - Streams right. Input arrives on standard input and the cleaned text goes to standard output.
- Options justified. You chose
-b,-f,-h,-xor-pbecause the downstream consumer needs that behaviour. - Original safe. You inspected the output and left the original input untouched.