188

When I search for tabs in a file with (e)grep I use the litteral tab (^v + <tab>). I can not utilize \t as a replacement for tabs in regular expressions. With e.g. sed this expression works very well.

So is there any possibility to use a non-litteral replacement for <tab> and what are the backgrounds for a non working / not interpreted \t ?

smci
  • 107
  • 4
Lasall
  • 3,673
  • 4
  • 29
  • 33

4 Answers4

262

grep is using regular expressions as defined by POSIX. For whatever reasons POSIX have not defined \t as tab.

You have several alternatives:

  • tell grep to use the regular expressions as defined by perl (perl has \t as tab):

    grep -P "\t" foo.txt
    

    the man page warns that this is an "experimental" feature. at least \t seems to work fine. but more advanced perl regex features may not.

  • use printf to print a tab character for you:

    grep "$(printf '\t')" foo.txt
    
  • use the literal tab character:

    grep "^V<tab>" foo.txt
    

    that is: type grep ", then press ctrl+v, then press tab, then type " foo.txt. pressing ctrl+v in the terminal causes the next key to be taken verbatim. that means the terminal will insert a tab character instead of triggering some function bound to the tab key.

  • use the ansi c quoting feature of bash:

    grep $'\t' foo.txt
    

    this does not work in all shells.

  • use awk:

    awk '/\t/'
    
  • use sed:

    sed -n '/\t/p'
    

See the wikipedia article about regular expressions for an overview of the defined character classes in POSIX and other systems.

Lesmana
  • 18,126
  • 8
  • 52
  • 49
  • basing on enzotib's answer let me add the following: `grep $'\t' foo.txt` (but I would usually write `fgrep` instead of `grep`) – Walter Tross Feb 21 '13 at 10:16
  • 1
    Perhaps worth noting that BSD (including OSX) grep, lacks the -P option. – TextGeek Feb 08 '18 at 18:43
  • 1
    From the man page `This is highly experimental and grep -P may warn of unimplemented features.` Probably not a good idea to use `-P` in legacy systems. The `printf` choice is better – Avindra Goolcharan Apr 10 '18 at 18:57
18

It is not exactly the answer you would want to hear, but a possible use of escape sequences is provided by bash

command | grep $'\t'

(do not put it into double quotes!).

Ravexina
  • 54,268
  • 25
  • 157
  • 179
enzotib
  • 92,255
  • 11
  • 164
  • 178
  • 2
    Indeed, I suggest that @enzotib edit the answer to be simply `grep $'\t'`. – Teemu Leisti Jun 04 '13 at 12:01
  • It should be stressed that this is a feature of bash and will (silently!) do the wrong thing if executed by some other shell (such as dash, which is the default for shell scripts on Ubuntu and others) – xjcl Aug 26 '17 at 14:00
  • @xjcl I never heard of `dash` being the default on Ubuntu - my Ubuntu always had `bash`. Can you back that statement up with any source, please? – jena Sep 30 '20 at 11:51
  • 1
    @jena bash is the default for interactive sessions. But non-interactive scripts default to /bin/sh which is a link to dash. You can verify this with `ls -la /bin/sh` – xjcl Sep 30 '20 at 20:22
  • @xjcl - interesting, I really never encountered it until now. Anyway, the question is tagged with `bash` so I think it's "stressed" enough. – jena Oct 12 '20 at 14:14
  • @jena If you use it interactively or in a .bashrc file you will be fine, but if you use it in cron for example this will bite you (as cron defaults to `/bin/sh`, not bash) – xjcl Oct 12 '20 at 15:04
2

awk '/\t/' is my favorite workaround:

printf 'a\t\nb' | awk '/\t/'

Output: a\t.

Ciro Santilli OurBigBook.com
  • 26,663
  • 14
  • 108
  • 107
2

One can always resort to using ascii hex-code for tab:

$ echo "one"$'\t'"two" > input.txt                                 

$ grep -P "\x9" input.txt                                          
one two

$ grep $'\x9' input.txt                                            
one two
Sergiy Kolodyazhnyy
  • 103,293
  • 19
  • 273
  • 492