opscape

Text processing

expand

Convert tabs to spaces, keeping the columns where they were; unexpand does the reverse.

expand [OPTION...] [FILE...]

6 of 6 examples run in Debian 13.7 on 2026-10-31 · coreutils 9.7-3 · manual: expand(1)

expand replaces each tab with the number of spaces needed to reach the next tab stop, so the text looks exactly as it did but contains no tabs. Tab stops are every 8 columns by default; -t 4 makes them every 4, and a list like -t 10,20 sets explicit positions.

This matters when tabs render differently in different places: code reviews, web pages, terminals with other tab settings, or tools that count characters. Its companion unexpand (same package) turns leading runs of spaces back into tabs.

Examples

Replace tabs with spaces

expand data/inventory.tsv | cat -A
explain
output
name    qty     price$
widget  12      4.50$
gadget  3       19.99$
gizmo   5       12.00$

cat -A would show tabs as ^I; there are none left. Each tab became enough spaces to reach the next multiple of 8, so qty starts at column 9 on every line.

Tab stops every 4 columns

printf 'if ok:\n\tif ready:\n\t\treturn 1\n' | expand -t 4
explain
output
if ok:
    if ready:
        return 1

-t 4 treats each tab as up to 4 columns, the usual setting for code that was indented with tabs.

Tab stops at explicit positions

expand -t 10,16 data/inventory.tsv
explain
output
name      qty   price
widget    12    4.50
gadget    3     19.99
gizmo     5     12.00

With a list, the first tab on each line goes to column 10 and the second to column 16, giving a fixed-width table.

Convert only leading tabs

printf '\tkey\tvalue\n' | expand -i -t 4 | cat -A
explain
output
    key^Ivalue$

-i expands only the tabs in the indentation; the tab between key and value survives (^I). Useful when tabs inside strings must stay.

Turn leading spaces back into tabs

printf '        eight spaces\n' | unexpand -t 4 | cat -A
explain
output
^I^Ieight spaces$

unexpand -t 4 converts each 4 leading spaces into a tab, so 8 spaces become ^I^I.

Convert a file in place

expand -t 4 data/inventory.tsv > inventory.txt && mv inventory.txt data/inventory.tsv
grep -c $'\t' data/inventory.tsv
outputexit 1
0

expand cannot edit a file in place, so write to a new file and rename it. Afterwards grep -c finds 0 lines with a tab, and exits with 1 because nothing matched.

Common pitfalls

  • expand file > file empties the file before expand reads it. Write to a temporary file and mv it back.

  • Expanding tabs in a Makefile breaks it: recipe lines must start with a real tab. Use expand -i carefully there, or not at all.

  • unexpand without -a only converts leading blanks; pass -a to convert runs of spaces everywhere on the line.

GNU vs BSD and macOS

The examples above ran the GNU/Linux version. These are the differences that matter on macOS and the BSDs (written from their documentation, not run here).

  • expand -t and unexpand -t/-a work on both GNU and BSD/macOS; -i (initial tabs only) is GNU.

Options worth knowing

A selection, described in our own words. For the full list, see expand(1) or expand --help.

OptionWhat it does
-t, --tabs N|LISTTab stops every N columns, or at the listed column positions.
-i, --initialOnly convert tabs before the first non-blank character.

Related