In an earlier article we discussed using the expand command to convert tabs to spaces. Conversly, you can use unexpand to convert spaces to tabs. The GNU Core Utilities packages provides both of these text utilities. Let's take a look at how to use unexpand and it's options.

There is one major difference between how expand and unexpand work. By default, expand will convert all tabs to spaces unless you provide the -i option. The unexpect utility converts only initial or leading spaces to tabs by default, unless you provide the -a option.

Convert Spaces to Tabs in a File

Below we have the same example code we used in the previous article. It was taken from our "How to Make a Countdown Timer in Bash" article.

Here we will use cat command and pipe it to the tr command to substitute the spaces for asterisks. This is just used as a visual aid to see the spaces.

[savona@putor ~]$ cat countdown.sh | tr " " "*"
#!/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

We can use the unexpand command to easily convert all of these spaces to tabs. Simply invoke the unexpand command and pass the file name as argument, like so:

[savona@putor ~]$ unexpand countdown.sh 

The above command will print the converted file to standard output (STDOUT). To save the new tab formatted output to a file, use a simple redirection.

[savona@putor ~]$ unexpand countdown.sh > tab-formatted-countdown.sh

Now we use the cat command with the -T (show tabs as ^I) to check the new file.

[savona@putor ~]$ cat -T tab-formatted-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

We have successfully converter all spaces to tabs in the countdown file.

Replace x Number of Spaces with a Tab

You can set the number of characters apart that unexpand places it's tabs. I know that seems like an odd sentence, let's take a look at some examples.

By default unexpand will replace every eight spaces with a tab. You can use the -t option to change that number to whatever you wish.

Here is the output of the unexpect command converting the default eight spaces to tabs.

savona@putor ~]$ unexpand countdown.sh | cat -T
#!/bin/bash
 hour=0
 min=0
 sec=10
^Iwhile [ $hour -ge 0 ]; do
...OUTPUT TRUNCATED...

As you can see there was eight spaces before the first while loop (last line above), which resulted in a single tab.

Now we will use the -t option to change it so unexpand replaces every two spaces with a tab. Since there is eight spaces, it should result in four tabs

[savona@putor unexpand]$ unexpand -t 2 countdown.sh | cat -T
#!/bin/bash
 hour=0
 min=0
 sec=10
^I^I^I^Iwhile [ $hour -ge 0 ]; do
...OUTPUT TRUNCATED...

If we used -t 1 it will result in a one to one swap for spaces to tabs. The result is eight tabs before the first while statement.

[savona@putor unexpand]$ unexpand -t 1 countdown.sh | cat -T
#!/bin/bash
^Ihour=0
^Imin=0
^Isec=10
^I^I^I^I^I^I^I^Iwhile [ $hour -ge 0 ]; do
...OUTPUT TRUNCATED...

Convert Sequences of Two or More Spaces to Tabs

As we touched on in the introduction, unexpand will only convert leading spaces to tabs. If you want to convert all blanks (sequence of two or more spaces) in the file, you must pass the -a option.

using unexpand to convert all spaces to tabs

The operation of this option is a little convoluted. Here is how the texinfo manual for GNU Core Utilities explains it.

Also convert all sequences of two or more blanks just before a tab
stop, even if they occur after non-blank characters in a line.

GNU Core Utilities Manual

Conclusion

The unexpand command is also a niche utility like it's counter command expand. In this article we discussed using unexpand to convert spaces into tabs. There are many ways to accomplish this, but none and simple as invoking a single command.

The GNU Core Utilities also provides the expand command.

Resources