I found that

setterm -regtabs 4

doesn't work in xterm or urxvt.

But, this

xterm_set_tabs () { 
  export $TERM;
  setterm -regtabs 4

will circumvent the problem.

But, I suspect it is suboptimal as (1) I get a gfx bug I can't otherwise explain (at least, if I get the tab stuff right that possibility is ruled out), and (2) when I ssh to my school's Solaris, and run emacs -nw, it says the terminal "linux" is unknown! So then I have to change it back to "xterm". Of course, this is silly as all the while I'm using the same terminal.

Also, perhaps not relying on tabs at all is a good rule of thumb!


The setterm utility is intended for use with the Linux console. According to the console_codes manual page:

The Linux console implements a large subset of the VT102 and ECMA-48/ISO 6429/ANSI X3.64 terminal controls, plus certain private- mode sequences for changing the color palette, character-set mapping, and so on.

Since the program is hard-coded,

/* -regtabs. */
if (ctl->opt_regtabs && vc_only(ctl, "--regtabs")) {
    int i;

    fputs("\033[3g\r", stdout);
    for (i = ctl->opt_rt_len + 1; i <= TABS_MAX; i += ctl->opt_rt_len)
        printf("\033[%dC\033H", ctl->opt_rt_len);

it just happens to work with xterm since xterm implements VT100 controls (plus more).

As for large subset, that is debatable. In a quick count of the items in console_codes, I see 79 control sequences. That is far less than any of the xterm look-alikes documented in the xterm FAQ Comparing versions, by counting controls. By itself, 79 is not large. The VT102 itself (not an xterm look-alike) had 104. ISO-6429 (aka ECMA-48) documents 20 modes and 162 sequences. Whether you count the total as 182 or 162, 50% is not a large subset.

Rather than using a Linux console utility, there is a more portable choice: the tabs utility (in POSIX as well as Solaris). It is part of the ncurses utilities (and probably installed on your Linux system).

For the example given in the question, you could do this:

tabs -4

That uses the terminal database, rather than being hard-coded. Tabs and the control sequences to set them are documented in ECMA-48 and other places such as the terminfo(5) manual page.

And tabs works with xterm.

  • 1
    Where has that been all my life?! Some program I use is forever cocking up my tab stops, and I don't know (or care) which one it is. I just wanted my tab stops back. What's the procedure for hijacking a question so I can mark it answered? The embarrassing part is that a simple man -k tab|grep -i -v table |grep -i -v database would have uncovered it decades ago. Sep 8 '17 at 15:04

Many terminals support escape sequences that set tab stops. The capability has even an entry in terminfo(5): tbc (clear all tabs) and hts (horizontal tab set).

$ tput tbc; echo aaaaaaaaaaaaaaaaaaaaa$(tput hts); echo 'a\tb'
a                    b

Above we set a tab stop at the end of those aaaaaaaa, and we see the result on next line.

So, to set the tab stops, every 4 colums, we need:

tbc=$(tput tbc) hts=$(tput hts) cuf4=$(tput cuf 4)
printf '%s\r' "$tbc"
while [ "$i" -lt "$COLUMNS" ]; do
  printf %s "$cuf4$hts"
  i=$(($i + 4))
printf '\r'

Or you can also set tab stops at irregular intervals. Above we used "tput cuf" to move the cursor forward, while in the first example we used "aaaa". You can do:

printf '\r%s' "${tbc}aaaa${hts}aaaaa${hts}aaaaaaaa${hts}"

to set one tab stop at the 4th column, then the next one, 5 columns further...

  • Will this set the general tab width so that \t = " " if the tab width is 4? (Imagine four spaces, seems I can't write that.) Aug 26 '12 at 21:03
  • OK, I see you've made an edit, answering my comment above. You seem to know a lot about this... Check out my answer below, is there a practical difference or are your solution simply much cooler? Aug 29 '12 at 2:35
  • Hello again, just tried this and it breaks the cursor movement in emacs -nw just like my solution below. Sep 1 '12 at 17:13

You can set the environment variable temporarily without needing to export it to your whole session using env:

env TERM=linux setterm -regtabs 4
  • That is better. Aug 26 '12 at 22:42
  • Tried this, same problem as described in my post, and in the comment to sch's post. Sep 1 '12 at 17:36

In response to @Jim Paris:

Note that that only works for terminals that support the same escape sequences as linux virtual terminals to set tabs (and move the cursor forward).For instance, using "cat -v", we can see what sequence setterm is sending:

$ TERM=linux setterm -regtabs 4 | cat -vte

Luckily, it's the same sequences as supported by xterm:

~$ TERM=xterm tput tbc | cat -vte
~$ TERM=xterm tput hts | cat -vte
~$ TERM=xterm tput cuf 4 | cat -vte

And as it's the case of vt100, it's likely to be the case of most termnial emulators.

  • Better yet would probably be to set it native in xterm, urxvt, etc., not going sideways to the Linux virtual terminal. I suspect there is an .Xresources option for this; I'll keep looking. (Above, isn't it enough with cat -t?) Aug 27 '12 at 9:19

OK, I've read man xterm and there is no mention of tab width. I'm starting to think it is easiest just to reset TERM. In .bashrc:

function xterm_set_tabs () {
  export $TERM
  setterm -regtabs 4
  export $TERM

if [ `echo $TERM` == "xterm" ]; then

Edit: This works for the problem described, but it has the side effect that when I run emacs -nw the cursor movement is messed up. As that is very serious, this is not an acceptable solution to the problem. (I'm unsure about site policy - should I remove my answer, or should I leave it so others will learn from the mistake as well? Obviously, I think it should remain. Anyhow, back to the drawing board.)

  • TERM=linux setterm -regtabs 4 is how you set the TERM variable to linux only for the setterm command. Are you sure you'll run that only in xterm terminals? Aug 29 '12 at 6:00
  • So far the above has worked, the display in xterm is correct and I can ssh and then emacs -nw, but I'm absolutely not sure of any under the hood workings in this case. There are a lot of suggestions already, if you know their pros and cons, do tell, that's why we are here :) Aug 29 '12 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.