Programmers have been arguing over the use of spaces versus tabs forever. It was hysterically depicted in the HBO hit series Silicon Valley. If you are on the "spaces" side of that argument, you will really enjoy this read. In this tutorial we are going to discuss a simple way to convert tabs into spaces using the expand command.

If you are "team tabs" maybe you will enjoy the unexpand command, which converts spaces to tabs.

The expand command is part of the GNU Core Utilities, which means it is available on just about any Linux system. It's main function is to convert tabs to spaces in a file. It has a few simple options, but like most of the core utils, it does one job really well.

Convert Tabs to Spaces in a File

Below we have some code taken from the "How to Make a Countdown Timer in Bash" article.

Sample code that is indented using tabs

If we use the cat command with the -T option (Show tabs as ^I) we can see that this file is indented using tabs. This would make Richard Hendricks very happy!

[savona@putor ~]$ cat -T countdown.sh 
#!/bin/bash
 hour=0
 min=0
 sec=10
^Iwhile [ $hour -ge 0 ]; do
^I^I while [ $min -ge 0 ]; do
^I^I^I while [ $sec -ge 0 ]; do
^I^I^I^I echo -ne "$hour:$min:$sec\033[0K\r"
^I^I^I^I let "sec=sec-1"
^I^I^I^I sleep 1
^I^I^I done
^I^I^I sec=59
^I^I^I let "min=min-1"
^I^I done
^I^I min=59
^I^I let "hour=hour-1"
^I done

However, some people prefer spaces. This is were the expand command comes in handy. It allows you to easily convert all of the tabs in this file to spaces. Simply pass the filename as an argument to the expand command like so:

[savona@putor ~]$ expand countdown.sh 

This will print the newly formatted file to standard output (STDOUT). To save it to a new file, simply redirect it to a file.

[savona@putor ~]$ expand countdown.sh > space-formatted-countdown.sh

Now we can test it again with the cat command.

[savona@putor ~]$ cat -T space-formatted-countdown.sh 
#!/bin/bash
 hour=0
 min=0
 sec=10
        while [ $hour -ge 0 ]; do
                 while [ $min -ge 0 ]; do
                         while [ $sec -ge 0 ]; do
                                 echo -ne "$hour:$min:$sec\033[0K\r"
                                 let "sec=sec-1"
                                 sleep 1
                         done
                         sec=59
                         let "min=min-1"
                 done
                 min=59
                 let "hour=hour-1"
         done

Here we can see that all the tabs have been converted to spaces!

Replace Tabs with x Number of Spaces

By default the expand utility will replace a tab with eight spaces. You can set the number of spaces you prefer by using the -t (--tabs=N) option. In the example below, we first replace all tabs with four spaces, then with two spaces.

using the expand command to convert tabs to spaces

Convert Only Leading Tabs to Spaces

Another feature of the expand utility is the -i (--initial) option. This conveniently allows you to convert only leading tabs in the file.

[savona@putor ~]$ cat -T test.txt 
This^Iis^Itab^Iseperated
^Ithis follows a tab
^Ithis follows a tab and ends with one^I
This line has a tab here^Iand two here^I
This line has a tab here^Iand a space and tab  ^I^I  ^I^I

[savona@putor ~]$ expand -i test.txt > new.txt

[savona@putor ~]$ cat -T new.txt 
This^Iis^Itab^Iseperated
        this follows a tab
        this follows a tab and ends with one^I
This line has a tab here^Iand two here^I
This line has a tab here^Iand a space and tab  ^I^I  ^I^I

As you can see, using expand -i only converted the leading tabs into spaces. Any tab following a non-blank is left intact.

Conclusion

The expand command is a niche utility but can be very useful. Of course there are many other ways to do replace tabs with spaces (sed?). However, writing a sed command for this is much more effort than using expand.

An interesting tidbit is that the GNU Core Utilities package also provides a unexpand command that allows you to convert spaces to tabs. We will discuss that in a future article.

Resources and Links