Linux convert tabs to spaces; spaces to tabs in shell scripts (Bash)

Linux convert tabs to spaces with expand; convert runs of spaces to tabs with unexpand; tab in bash with $'\t' and printf; unix shell scripts conversion for tab- vs space-delimited text and aligned columns.

Published

Updated

Read time 3 min read

Reviewed byDeepak Prasad

Linux convert tabs to spaces; spaces to tabs in shell scripts (Bash)

Converting between tab- and space-separated text is a routine pipeline task: log fields, CSV-ish exports, and Makefile recipes (where a leading tab still matters). Turning tabs into spaces is usually expand; turning repeated spaces into tabs is unexpand. For tab literals in Bash, use $'\t' or printf '\t' instead of pasting a literal tab character.

Tested on Ubuntu 25.04, GNU coreutils expand / unexpand 9.5, Bash 5.2.37.


Linux convert tabs to spaces (expand)

expand reads text and replaces tab characters with spaces so that tab stops line up at fixed columns (default often 8; override with -t).

bash
printf '%s\n' $'name\tvalue\nfoo\tbar' | expand -t 8 | cat -A
text
name    value$
foo     bar$

cat -A shows ^I for a tab and plain spaces otherwise—handy when verifying conversion in a script:

bash
expand -t 4 input.txt > output.txt

Pipe instead of files when you only need a one-off conversion step in a larger pipeline.


Convert spaces to tabs (unexpand, sed, tr)

unexpand (GNU coreutils)

unexpand merges leading spaces (and optionally other blanks) into tabs.

bash
printf '    line with 4 leading spaces\n' | unexpand -t 4 --first-only | cat -A
text
^Iline with 4 leading spaces$

Flags worth reading in man unexpand: -a (all blanks on the line, not only leading), tab width -t.

One-line sed / tr for simple space runs

Collapse multiple spaces and turn separators into tabs when the line is predictable:

bash
printf '%s\n' 'col1  col2   col3' | tr -s ' ' | sed 's/ /\t/g' | cat -A
text
col1^Icol2^Icol3$

For heavier field logic, awk is often clearer—see awk examples.


Tab in bash ($'\t', printf, heredocs)

Tab literals in Bash:

bash
printf 'A%sB\n' $'\t' | cat -A
printf 'A\tB\n' | cat -A
text
A^IB$
A^IB$

In a <<EOF heredoc, a real tab character is a tab; many style guides prefer <<'EOF' when you do not want expansions, which also freezes tabs literally. Avoid invisible tabs in conditionals—they are easy to miscount in review.


Aligned columns: prefer explicit widths over fragile tab math

Older scripts sometimes measured string length with wc -c and expr to decide how many spaces to print. That breaks on multi-byte characters and is harder to read than printf field widths:

bash
printf '%-12s : %s\n' "col1" "col2" "col3" "col4"
text
col1         : col2
col3         : col4

If you truly need tab stops between dynamic fields, build the line with $'\t' between segments, then run expand -t n once for consistent viewing.


Summary

Use expand to convert tabs to spaces (tune stops with -t). Converting runs of spaces to tabs leans on unexpand or small sed / tr filters when the layout is simple. Tab literals in Bash are $'\t' or printf '\t'; verify with cat -A. For human-readable tables in scripts, fixed-width printf is usually more robust than hand-tuned tab padding. GNU details live in man expand and man unexpand.

Further reading: GNU expand manual, GNU unexpand manual. For timed loops that sometimes format output, see bash while loop until a specific time.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …