When I am in vim I can change the tab size with the following command:

:set ts=4

Is it possible to set tab size for cat command output too?


The first command here emulates the formatting you see in vim. It intelligently expands tabs to the equivalent number of spaces, based on a tab-STOP (ts) setting of every 4 columns.

printf "ab\tcd\tde\n" |expand -t4   


ab  cd  de

To keep the tabs as tabs and have the tab STOP positions set to every 4th column, then you must change the way the environment works with a tab-char (just as vim does with the :set ts=4 command)

For example, in the terminal, you can set the tab STOP to 4 with this command;

tabs 4; printf "ab\tcd\tde\n" 


ab  cd  de
  • 2
    good to know (1). expand (from coreutils package) and tabs (from ncurses package) command, (2). and the meaning of ts is [T]ab [S]top Mar 12 '13 at 8:37

Just use the following code:

tabs -n

Where n is the number of spaces you want tabs to correspond too. In order to not having to do this every time you start the shell, just edit your .bash_profile in ~/ and add the above line to the end of the file.

For further info about the tabs command, refer to:

man tabs
  • 5
    Just beware that permanently changing your default tabs width might screw up other commands (for example ls out put may look not properly aligned). Feb 2 '14 at 14:58

There's no notion of tabs or tab stops in cat; the program just funnels the inputs to the output and treats tabs like any other character. If the output device happens to be a terminal, tabs will be handled according to whatever behavior the terminal is configured to provide.

Systems implementing POSIX.1 have a command called tabs(1) that will adjust the terminal's concept of how tabs should be displayed. Depending on a particular tab layout is not considered a good idea, as someone may send your file to some other device such as a printer that won't do what you intended.

When you adjust ts in vim (or plain vi), all you're doing is adjusting how the editor interprets tab characters when displayed. It has no bearing on what ends up in the file.

  • Thanks for explanation. How is the printer configured to treat tabs?
    – B Faley
    Feb 27 '12 at 19:36
  • Most printers treat them the same way as most terminals do by default: the left margin and every eight characters afterward.
    – Blrfl
    Feb 27 '12 at 19:59

Based on the above answers and examples, it would seem that the actual command the OP wanted is...

cat somefile | expand -t4

This works for me on Red Hat 6.4.


To expand on the already given answers, expand can also take a list of tab stop positions. This is useful if the content lengths of the varlious columns varies a lot.

I came over this requirement today when I wanted to make the output of openssl ciphers more readable:

$ openssl ciphers -v 'HIGH'|tr -s ' ' '\t'|expand -t31,41,57,70,90
ECDHE-RSA-AES256-GCM-SHA384    TLSv1.2   Kx=ECDH         Au=RSA       Enc=AESGCM(256)     Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384  TLSv1.2   Kx=ECDH         Au=ECDSA     Enc=AESGCM(256)     Mac=AEAD
ECDHE-RSA-AES256-SHA384        TLSv1.2   Kx=ECDH         Au=RSA       Enc=AES(256)        Mac=SHA384
ECDHE-ECDSA-AES256-SHA384      TLSv1.2   Kx=ECDH         Au=ECDSA     Enc=AES(256)        Mac=SHA384
ECDH-ECDSA-AES128-SHA          SSLv3     Kx=ECDH/ECDSA   Au=ECDH      Enc=AES(128)        Mac=SHA1
AES128-GCM-SHA256              TLSv1.2   Kx=RSA          Au=RSA       Enc=AESGCM(128)     Mac=AEAD
AES128-SHA256                  TLSv1.2   Kx=RSA          Au=RSA       Enc=AES(128)        Mac=SHA256
AES128-SHA                     SSLv3     Kx=RSA          Au=RSA       Enc=AES(128)        Mac=SHA1

CAMELLIA128-SHA                SSLv3     Kx=RSA          Au=RSA       Enc=Camellia(128)   Mac=SHA1
PSK-AES128-CBC-SHA             SSLv3     Kx=PSK          Au=PSK       Enc=AES(128)        Mac=SHA1

Using only expand -t31 would blow up the width of the output from around 100 characters to more than 160 characters.

  • 1
    An easier way to do that is to use column: openssl ciphers -v 'HIGH' | column -t
    – muru
    Feb 10 '16 at 15:57

For X terminal emulators (eg. $TERM is xterm, st, etc.):

$ tabs -N

For virtual consoles (no X Server, only text console where $TERM is linux, etc.):

$ setterm --tegtabs N

Where N is an integer number of spaces to be used for TAB.

Sed way insead of tr which translates SET1 to SET2 of characters in 1:1 'proportions':

$ sed 's/\t/    /g' FILENAME
        spaces here

Many terminals support setting variable tab stops. Those that are vt100, linux and or support the EMCA-48 standard do, most terms on linux support setting tab size: xterm and family (uxterm, urxvt) xfce4-terminal, luit, Terminal, SecureTTY, among others.

So wrote a script a few years back to set my tabs at login to every 2 spaces -- used to use 4, then 3 for a short bit, and now at 2....

So now, if I 'cat' a file, tabs in the file will expand to my terminal's setting.

If I got through vim or more, they do their own tab expansion, but alot of utils use tabs.

Will include the script here for reference, and or personal use:

#!/bin/bash  -u
#console_codes(4) man page... vt100/2 et && EMCA-48 standard
# (c) la walsh (2013) -- free to use and modify for personal use.
#                     -- optionally licenced under Gnu v3 license.

# v0.0.3    - try to reduce tabcols to minimal set to reproduce.
# v0.0.2    - set tabs for full terminal width (try to get term width)

shopt -s expand_aliases extglob
alias my=declare        
alias int='my -i'       array='my -a' intArray='my -ia'   string=my

my _Pt=$(type -t P)
[[ $_Pt && $_Pt == function ]] && unset -f P
alias P=printf
unset _Pt

P -v clrallts  "\x1b[3g"    #Clear All TabStops
P -v hts       "\033H"      #Horizontal TabStop
P -v cpr       "\x1b[6n"    #Current Position Report

getcols() {                 # try to read terminal width
  local sttyout="$(stty size </dev/tty)"
  int default_cols=80
  if [[ -n ${COLUMNS:-""} && $COLUMNS =~ ^[0-9]+$ ]]; then 
    default_cols=$COLUMNS; fi
  [[ -z ${sttyout:-""} ]] && { echo $default_cols; return 0; } 
  int cols="${sttyout#*\ }"
  echo -n $[cols<2?default_cols:cols]
  return 0

getpos () {
  string ans    wanted=${1:-xy}
  int attempt=0 max_attempt=1   # in case of rare failure case
                                # use 'attempt' value as additional
                                # time to wait for response
  while : ; do
    ( ( P "\x1b[6n" >/dev/tty) & 2>/dev/null )  
    read  -sd R -r -t $[2 + attempt] ans </dev/tty; 
    int x=0-1 y=0-1
    if ! x="${ans#*;}" y="${ans%;*}" 2>/dev/null  || 
      ((x==-1||y==-1)); then
      ((attempt+=1 < max_attempt)) && continue
  break; done
  string out=""
  [[ $wanted =~ x ]] && out="$x"
  [[ $wanted =~ y ]] && out="${out:+$x }$y"
  [[ $out ]] && echo -n "$out"

declare -ia tabs

get_tabs () {
  P "\r"
  int pos=0 oldpos=0-1
  while ((oldpos!=pos));do
    ((pos)) && tabs+=($pos)
    P "\t"
    pos=$(getpos x)
  P "\r"
  return 0

# Note: this func uses ability to _read_ tabstops as _proxy_ for setting them
# (i.e. it makes no sense to be able to read them if you can't set them)

test_tabset_ability () {
  string prompt="tty_tab:"
  int newcol=${#prompt}+1
  P "\r$prompt"
  int mycol=$(getpos x)
  ((mycol && mycol==newcol)) && return 0    ## return OK

  { P " Term tabset ability not detected mycol=${mycol:-''},"
    P " promptlen=$newcol)\n"; } >&2
  exit -1 

do_help_n_display_curtabs () {
  P " <n>   - set tab stop to N\r"
  intArray diffs;
  int last=1  cur i
  string eol=""
  get_tabs && {
    for ((i=0; i<${#tabs[@]}; ++i)); do
    intArray reverse_tabs_set=()
    int prevtab=0-1
    for ((i=${#diffs[@]}-2; i>0; --i)); do
      int thistab=${diffs[i]}
      if ((thistab!= prevtab)) ;then 
    P "current value: tty_tab "
      for ((i=${#reverse_tabs_set[@]}-1; i>=0; --i)); do
        P "%d " "${reverse_tabs_set[i]}"; done
    P "\r";
  get_tabs  && {
    P "(from 1, tabs skip to column: "
    P "%s " "${tabs[@]}"
    P "\r\n"

set_tabs () {
  int max_col=${1:=0-80}
  int tabstop=${2:-?"need a param for tabstop"}
  int tab=$tabstop        pos=0
  string str=""
  P $clrallts               ## reset old tabs
  while ((++pos<cols)) ;do  ## move across screen setting tabs
    str+=" "
    ((pos%tab)) || str+="$hts"
  P "\r$str\r"

int cols=$(getcols)

test_tabset_ability         ## exits if no ability

if (($#==0)) ; then
  exit 1
  set_tabs "$cols" "$@"

# vim: ts=2 sw=2

Hope it helps...


According to the manpage, cat can not do it on its own. But you can e.g. run the output from cat through tr filter to replace the tabs with any number of spaces you wish:

cat somefile | tr '\t' '  '

will replace the tab character with two spaces.

Update: as pointed out in the comments to this post, this actually does not work. Nevertheless, I'm keeping the answer as an example of how not to do it.

  • 3
    It's actually replacing '\t' with only one space, no matter how many spaces are in between the second pair of quotes ' '
    – B Faley
    Feb 27 '12 at 14:52
  • 3
    tr doesn't work that way.. each byte of arg 1 is substituted by each corresponding byte of arg 2..... Therefore printf '\t' |tr '\t' 'ळ' prints out a single byte whose hex value is \xE0 .. which is the first byte of the three UTF-8 encoded bytes which make up the character (whose Unicode CodePoint value is U+0933)
    – Peter.O
    Feb 27 '12 at 14:59
  • Ah, of course. Thanks for catching my silly mistake!
    – Petr Uzel
    Feb 27 '12 at 15:07

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.