Convert Tabs to Spaces with expand in Linux
Learn how to replace tab characters with spaces in Linux using expand, control tab stops, verify whitespace, and safely replace files.
A tab character and a space character are both whitespace, but they do not behave the same way. A tab character is a horizontal control character, commonly written as \t, that advances text to a tab stop. A space character is a literal blank character with a fixed width in a monospaced display.
The expand command converts tabs to literal spaces. This is useful when a file must contain spaces, or when another tool displays tabs inconsistently. It is also useful for preparing plain text for systems that expect fixed spacing.
How tabs differ from spaces
A tab does not inherently mean “four spaces” or “eight spaces.” It means “move forward to the next configured tab stop.” A tab stop is a column position where tabbed text can align.
For example, with repeated four-column tab stops at columns 4, 8, 12, and so on:
- A tab beginning at column 1 may insert four spaces.
- A tab beginning at column 3 may insert two spaces to reach column 4.
- A tab beginning at column 5 may insert four spaces to reach column 8.
Therefore, expanding a tab according to tab stops is different from replacing every tab with one space. The -t 1 option performs the latter operation, while settings such as -t 4 preserve four-column tab-stop behavior.
What the expand command does
expand is a standard Linux and Unix utility for replacing tab characters with spaces in text. It reads either named files or standard input and writes the converted text to standard output.
expand input.txt
With this command, expand reads input.txt and prints the converted content in the terminal. It does not modify input.txt directly.
It can also read standard input. Standard input is the stream a command receives when data is piped to it or when no input file is supplied:
printf 'name\tvalue\n' | expand -t 1
The converted result is printed to standard output. Use shell redirection to save that output.
Basic tab conversion
Use the default tab stops
To convert a file using the command's default tab-stop behavior, run:
expand input.txt > output.txt
On typical Linux implementations, the default uses tab stops every eight columns. The original file remains unchanged, while output.txt receives the converted text.
Inspect the destination before replacing the source:
cat -te output.txt
When the conversion is correct, you can decide whether to keep both files or use a safe replacement workflow.
Replace every tab with one space
Use -t 1 when the requirement is exactly one literal space for every tab character:
expand -t 1 input.txt > output.txt
This does not preserve column alignment. For example, two tabs become two spaces regardless of where they occur. That behavior is appropriate for some text-processing tasks, but not for every table or source file.
The long option is equivalent:
expand --tabs=1 input.txt > output.txt
Control the tab width with -t or --tabs
The -t or --tabs option sets tab-stop positions. With one numeric value, the value is used as a repeated tab width.
| Option | Meaning | Example | Result |
|---|---|---|---|
-t 1 | Use one-column repeated stops | expand -t 1 input.txt | Each tab becomes one space |
-t 4 | Use four-column repeated stops | expand -t 4 input.txt | Advance to the next multiple-of-four column |
-t 8 | Use eight-column repeated stops | expand -t 8 input.txt | Advance to the next multiple-of-eight column |
--tabs=1 | Long form of the one-space setting | expand --tabs=1 input.txt | Each tab becomes one space |
No -t option | Use the default tab-stop behavior | expand input.txt | Usually uses stops every eight columns |
For a four-column setting, the number of inserted spaces depends on the current column:
| Starting column | Tab setting | Spaces inserted | Explanation |
|---|---|---|---|
| Column 1 | -t 4 | 4 | The next stop is column 5 when columns are counted from the first character position. |
| Column 3 | -t 4 | 2 | The tab reaches the next four-column boundary. |
| Column 5 | -t 4 | 4 | The next boundary is four columns away. |
| Any column | -t 1 | 1 | Every tab is replaced with exactly one space. |
The exact column numbering convention is less important than the rule: with normal tab stops, a tab advances to the next stop, so its replacement length can vary according to the text before it.
Input and output patterns
Read one named file
expand input.txt > output.txt
This reads one file and writes a separate converted file.
Process piped input
printf 'name\tvalue\n' | expand -t 1
Because no input filename is supplied, expand reads standard input. Without a final redirection, the result appears in the terminal:
printf 'name\tvalue\n' | expand -t 1 > output.txt
Process multiple files
expand -t 4 first.txt second.txt > combined.txt
When multiple files are supplied, their converted contents are written consecutively to the same standard-output stream. The result is a combined output file; file boundaries are not automatically recorded. If each source needs its own destination, process them separately, for example:
for file in *.txt; do
expand -t 4 "$file" > "$file.expanded"
done
Quote filenames such as "$file" so spaces and shell metacharacters in names are handled safely.
Verify that tabs were removed
Whitespace can look aligned even when tabs are still present. Use a representation that makes invisible characters visible.
Use cat -te
cat -te input.txt
GNU cat -te commonly displays a tab as ^I. Line endings may also be shown with a $ marker. Ordinary spaces remain visually blank, so compare the source and destination:
cat -te input.txt
cat -te output.txt
The converted output should no longer contain ^I markers.
Use sed -n l
sed -n l input.txt
sed -n l output.txt
This prints a visible, escaped representation of each line. A tab is commonly represented as \t in this output, depending on the implementation and locale.
Many editors also have a setting to display whitespace. Use that mode when available, but do not rely only on visual alignment: tabs and spaces can appear identical in a normal editor view.
Safely replace the original file
Do not redirect directly back to the input path:
expand -t 1 input.txt > input.txt
The shell opens the redirection target before expand starts reading. Opening the same path for writing can truncate the file, leaving expand with an empty or incomplete input.
Write to a temporary file, check the result, and then move it into place:
expand -t 1 input.txt > input.txt.tmp && mv input.txt.tmp input.txt
The && operator runs mv only when expand exits successfully. For important files, preserve a backup first:
cp -- input.txt input.txt.bak
expand -t 1 input.txt > input.txt.tmp && mv input.txt.tmp input.txt
Verify the temporary or replaced file before deleting the backup. A temporary filename should not already be used by another process, and you should ensure that the destination has enough free space.
| Approach | Command pattern | Safe for source file | Reason |
|---|---|---|---|
| Separate output file | expand input.txt > output.txt | Yes | The source and destination paths differ. |
Temporary file followed by mv | expand input.txt > input.txt.tmp && mv input.txt.tmp input.txt | Yes, when verified and controlled | The source is read before the completed temporary result replaces it. |
| Direct redirection to the input filename | expand input.txt > input.txt | No | The shell can truncate the input before expand reads it. |
Scope and limitations
expandis intended for text input. Do not use it on binary files, because changing byte sequences can corrupt them.- It changes tab characters wherever they occur, including leading indentation and tabs embedded between words.
- In source code, indentation may be part of a style convention, and some languages or tools interpret whitespace specially.
- Makefile recipe lines conventionally require tabs. Converting them to spaces can make the Makefile fail.
- In TSV data, tabs are field separators. Replacing them with spaces changes the data structure and can break imports.
- Before conversion, determine whether the tabs are merely presentation whitespace or meaningful content.
Troubleshooting
The text no longer lines up
If you used -t 1, every tab became one space, so tabular alignment was not preserved. Use a suitable width such as -t 4 or -t 8, or confirm that one-space replacement is really required.
The source file is empty or damaged
The likely cause is redirecting output to the same filename as the input. Restore the original or a backup, then write to a different temporary or destination path before renaming it.
Tabs still seem to be present
You may be viewing the wrong file, or your viewer may render tabs and spaces alike. Run cat -te output.txt or sed -n l output.txt and look for tab markers such as ^I or \t.
A Makefile or code file stops working
Tabs may be syntactically required, especially on Makefile recipe lines. Restore the required tabs and avoid applying expand blindly to files whose whitespace has semantic meaning.
Delimited data no longer imports correctly
A TSV file uses tab characters as field separators. Keep it unchanged, or deliberately convert it to a format such as CSV using a tool that handles quoting and embedded delimiters correctly.
The reverse operation: unexpand
unexpand is the companion utility. It can replace suitable sequences of spaces with tabs:
unexpand output.txt > restored-tabs.txt
This is not necessarily a lossless reversal of every expand operation. Once tabs have become spaces, the original tab boundaries may be impossible to determine, especially after using -t 1 or when spaces already existed in the source.
Quick reference
# Default tab stops
expand input.txt > output.txt
# One literal space per tab
expand -t 1 input.txt > output.txt
expand --tabs=1 input.txt > output.txt
# Repeated four- or eight-column stops
expand -t 4 input.txt > output.txt
expand -t 8 input.txt > output.txt
# Convert piped input
printf 'name\tvalue\n' | expand -t 1
# Inspect invisible whitespace
cat -te input.txt
sed -n l input.txt
# Safely replace a file
expand -t 1 input.txt > input.txt.tmp && mv input.txt.tmp input.txt
# Attempt a related reverse conversion
unexpand output.txt > restored-tabs.txt
For related command-line techniques, see Show the Full Path Of Shell Commands and the Linux command-line topics.