>_cmd.script

unexpand

Convert runs of spaces back into tabs

Text Processing

By CMD Script Team · 4 min read · Last updated

SYNTAX
unexpand [OPTIONS] [FILE...]

Options

Command options and flags
FlagDescription
-aConvert all runs of spaces to tabs, not just leading (initial) whitespace
-tSet tab stop width (or a comma-separated list of stops), default is 8
--first-onlyConvert only the first sequence of spaces on each line, even with -a

Distribution compatibility

  • Ubuntu
  • Debian
  • Fedora
  • Arch
  • macOS

What it does

unexpand scans its input for runs of space characters and converts them back into tab characters, based on a configurable tab-stop width (default 8). By default it only converts leading whitespace (indentation); the -a flag extends conversion to space runs anywhere on the line. It's the exact inverse of expand, useful when a workflow or tool (like make) specifically requires literal tabs.

Beginner examples

  • unexpand file.txt — convert leading spaces back to tabs using 8-space stops
  • unexpand -a file.txt — convert all space runs, not just leading indentation
  • unexpand -t 4 file.txt — convert using 4-space tab stops
  • unexpand file.txt > file_tabs.txt — save the converted output to a new file
unexpand -t 4 spaced_code.py > tabbed_code.py

Advanced examples

  • Restore literal tabs in a Makefile whose recipe lines got space-indented by an editor: unexpand -t 8 Makefile > Makefile.fixed && mv Makefile.fixed Makefile
  • Convert column-aligned space-padded text back into tab-separated form: unexpand -a --first-only report.txt
  • Normalize a project from space-indentation to tab-indentation as part of a style migration: for f in src/*.c; do unexpand -t 4 "$f" > "$f.tmp" && mv "$f.tmp" "$f"; done
  • Round-trip check with expand to confirm no content was lost: unexpand -a file.txt | expand -t 8 | diff - file.txt
unexpand -a data_spaces.txt > data_tabs.tsv

Common mistakes

  • Redirecting output back onto the same input file (unexpand file.txt > file.txt), which truncates the file before unexpand can read it — always write to a temp file first.
  • Forgetting -a and being confused when spaces in the middle of a line (like padding between table columns) don't get converted — default behavior only touches leading whitespace.
  • Assuming unexpand and expand are perfectly symmetric for arbitrary text — a run of spaces shorter than a full tab stop won't convert to a tab, since that would change the visual alignment.
  • Using the wrong -t width, resulting in tabs that render at a different visual width than the original spaces did in your editor.

Tips

  • Use -a specifically for tabular data where columns are space-padded and you want a genuinely tab-separated file.
  • Verify the round trip: unexpand file | expand should reproduce the original spacing if the tab width matches what was used to create it.
  • Check make-related "missing separator" errors first for accidental space-for-tab conversion — cat -A Makefile | head reveals whether recipe lines start with ^I (tab) or spaces.

Best practices

  • Match the -t width to whatever tab width the destination tool or style guide expects (make recipes conventionally use a single tab regardless of visual width).
  • Never overwrite the source file directly via shell redirection; write to a new file and move it into place after confirming correctness.
  • Use -a deliberately and sparingly — converting all space runs can unexpectedly touch spacing inside strings or comments in source code, not just structural indentation.

Try it yourself

A simulated shell with a sample home directory — experiment freely, nothing leaves your browser. Type help to list supported commands.

Real-world use cases

  • Fixing a Makefile that fails with *** missing separator because an editor replaced leading tabs in recipe lines with spaces.
  • Converting a space-indented codebase back to tabs to comply with a team's .editorconfig or linter rule.
  • Compacting large space-padded tabular text exports into a smaller tab-separated format before storage or transfer.

Common interview questions

  • What is the relationship between expand and unexpand? They're inverses: expand converts tabs to spaces, unexpand converts runs of spaces back to tabs, both based on a configurable tab-stop width.
  • Why does unexpand only convert leading whitespace by default? Because converting arbitrary inline space runs could unintentionally alter the exact visual alignment or content of a line; leading indentation is the safe, common case, so -a is required to opt into converting everywhere.
  • Why would a Makefile need unexpand? make requires recipe lines under a target to start with a literal tab character; if an editor auto-converts tabs to spaces, unexpand -t 8 restores the required literal tabs.

Frequently Asked Questions

Why would I convert spaces back to tabs?

Tab-based indentation produces smaller files and matches some style guides (Makefiles, for instance, require literal tabs for recipe lines). unexpand converts space-indented text back into tabs to satisfy those requirements or personal style preferences.

How is unexpand different from expand?

expand converts tabs to spaces; unexpand does the exact opposite, converting runs of spaces into the equivalent tabs. By default unexpand only converts leading whitespace; use -a to convert space runs anywhere on the line.

Why does a Makefile break with 'missing separator' errors?

make requires recipe lines to start with a literal tab character, not spaces. If an editor converted your tabs to spaces, run unexpand -t 8 on the file (or fix the specific lines) to restore literal tabs before the leading whitespace on recipe lines.

Cheat sheet

Download a quick-reference cheat sheet for unexpand.