How do I grep
tab (\t) in files on the Unix platform?

- 39,467
- 16
- 112
- 140

- 20,805
- 32
- 86
- 99
-
71just use `grep "
– rook Aug 05 '13 at 15:19"`, it works (if first time: type `grep "` then press Ctrl+V key combo, then press TAB key, then type `"` and hit enter, voilà!) -
28ctrl+v is a REALLY BAD IDEA ! ... yes it may work from console command, but it may NOT WORK TO TYPE IT IN A SCRIPT (you are at the mercy of the editor, for example i use mcedit and ctrl+v DON'T work there) – THESorcerer Feb 21 '14 at 00:36
-
Related, but ***not*** a duplicate: *[Search for tabs, without -P, using 'grep'](http://stackoverflow.com/questions/4976715)* – Peter Mortensen Mar 13 '15 at 10:18
-
See also: https://askubuntu.com/questions/53071/how-to-grep-for-tabs-without-using-literal-tabs-and-why-does-t-not-work/53090#53090 (linked below as well) – shiri Jul 03 '17 at 16:39
-
5I don't think it is a “really bad idea”. It is just _one_ possible approach. It is nice to know it exists and know how to use it, and one must of course decide when it is appropriate or OK to use it (or not use it). My editor supports it but I would not use it in a script, sure, unless no other option was available. – Fernando Basso Aug 07 '20 at 10:43
22 Answers
If using GNU grep, you can use the Perl-style regexp:
grep -P '\t' *

- 3,782
- 4
- 16
- 33

- 391,730
- 64
- 469
- 606
-
It doesn't seem to work against my pattern. Attempting to use that syntax prints nothing. (Is the Mac OS X variant different?) – futureelite7 Feb 28 '10 at 15:42
-
2@futureelite: According to Apple's docs (http://developer.apple.com/Mac/library/documentation/Darwin/Reference/ManPages/man1/grep.1.html), the Mac OS X grep program should support the -P option. Consider creating a new question, on superuser.com. – unwind Feb 28 '10 at 16:17
-
3That's very good for GNU UNIX, but what about POSIX Solaris, AIX and HP-UX? Those don't know anything about `-P` option. – rook Aug 05 '13 at 15:17
-
32
-
-
The `
` solution of SamK (http://stackoverflow.com/a/4691757/2516301) works faster – vefthym Jun 06 '14 at 13:48 -
5
-
With brew installed GNU grep (on a mac) and zsh, I needed `ggrep -P -- '\t' *.txt`. Without `--` I get `conflicting matchers specified`!? – drevicko Jul 29 '21 at 03:44
The trick is to use $ sign before single quotes. It also works for cut and other tools.
grep $'\t' sample.txt

- 3,782
- 4
- 16
- 33

- 4,686
- 2
- 21
- 21
-
9Lifesavior tip saves lives! It does work in `zsh` as well, as far as I can tell. Could you comment on what the semantics of that `$` sign is? – Romain Jan 25 '12 at 15:16
-
3Doesn't work if the String contains anything other than '\t'. How would you search for "\t " (tab + space) for example? – Raman Apr 17 '13 at 15:05
-
7Raman: You can use `$'\t'' '`. A real example that shows it works also with sh (not only bash, which is not by default installed on Android) is `busybox grep -oE '^nodev'$'\t''fuse$' /proc/filesystems`. – v6ak Jul 21 '13 at 07:14
-
1
-
1
-
2@Raman it worked with normal letters also, e.g. `zgrep $'\tPara\t' *` - found "Para" surrounded by tabs via Ubuntu 14 bash – yetanothercoder Mar 10 '16 at 16:38
-
And if you need to combine that `\t` with other chars, use `$'\t\|[;.,|]'`. – James Brown Jun 09 '16 at 11:08
-
7I think $'...' is a bash idiom. Probably doesn't work in sh. Dunno about csh or tcsh. – Edward Falk Aug 31 '16 at 18:45
-
1I can confirm that $'' doesn't work with sh. But it does work in zsh. – Att Righ Feb 01 '17 at 15:15
-
1
-
1'echo -n $'\t' |xxd -ps' shows '09' (0x09 is TAB). @teambob and Att Righ, thanks for explaining. It is a bashism. – gaoithe Feb 24 '17 at 15:15
-
11From 'man bash': Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded ... – broeni Nov 22 '17 at 14:44
-
In addition to `xxd`, another way to examine is: `echo -n $'\t' | od -tx1` – daparic Oct 05 '18 at 23:46
-
With fish you just concatenate, without quotes around the `\t`. For example: `"abc"\t"def"`. – Raman May 25 '20 at 15:19
-
For those that are wondering: `echo -e '_\t_' | grep $'_\t_'` – Roel Van de Paar Aug 29 '20 at 00:40
-
And for those that are wondering more: `echo -e '_\t_' | grep -E $'_\t|_'` – Roel Van de Paar Aug 29 '20 at 00:41
I never managed to make the '\t' metacharacter work with grep. However I found two alternate solutions:
- Using
<Ctrl-V> <TAB>
(hitting Ctrl-V then typing tab) - Using awk:
foo | awk '/\t/'

- 2,094
- 3
- 17
- 18
-
6The `| awk '/\t/'` solution will work for all shells, platforms and systems. – Samveen Jun 29 '12 at 06:45
-
8+1 for the portable POSIX solution and not using bashisms, zshism, GNUism and linuxisms. – Jens May 05 '13 at 16:56
-
2ctrl-V is not useful if you want to copy-paste (from your notes or a script). Better use an explicit solution that has a visible '\t' , literal TABs (i.e. the ones that look like whitespace) are often converted to SPC when copypasting ... – plijnzaad Mar 07 '17 at 11:39
-
1`awk` works well here but in some tests on my machine with very large files it is about 30% slower than using `grep -P`. This might be trivial and irrelevant based on the use case, and `awk` may be better simply for readability and portability. – theferrit32 Sep 12 '19 at 16:37
One way is (this is with Bash)
grep -P '\t'
-P
turns on Perl regular expressions so \t will work.
As user unwind says, it may be specific to GNU grep. The alternative is to literally insert a tab in there if the shell, editor or terminal will allow it.

- 3,782
- 4
- 16
- 33

- 1,045
- 1
- 8
- 19
-
1
-
-
How do you add a tab? Does it not start the auto complete process when you press the tab button? (that might work in a bash script but not in the command line) – AntonioCS Apr 08 '11 at 13:57
-
1@AntonioCS as noted above by SamKrieg, in order to have the Shell let you type any character, just type CTRL-v first. See also http://askubuntu.com/questions/53071/how-to-grep-for-tabs-without-using-litteral-tabs-and-why-does-t-not-work – Denis Arnaud Aug 01 '12 at 13:55
-
2-P is specific to grep, not to any shell. -P should work in any shell, provided GNU grep is installed – plijnzaad Mar 07 '17 at 11:40
-
Another way of inserting the tab literally inside the expression is using the lesser-known $'\t'
quotation in Bash:
grep $'foo\tbar' # matches eg. 'foo<tab>bar'
(Note that if you're matching for fixed strings you can use this with -F
mode.)
Sometimes using variables can make the notation a bit more readable and manageable:
tab=$'\t' # `tab=$(printf '\t')` in POSIX
id='[[:digit:]]\+'
name='[[:alpha:]_][[:alnum:]_-]*'
grep "$name$tab$id" # matches eg. `bob2<tab>323`

- 10,763
- 7
- 51
- 69
-
2This is a bashism. The answers using echo or printf below are portable. – uncleremus Dec 02 '21 at 13:46
-
@uncleremus true, although the only Bashism is the syntax of `$''` which can be replaced by (kinda ugly) `"$(printf 'foo\tbar')"`; I think my answer shows that in second part. – Alois Mahdal Dec 09 '21 at 13:10
There are basically two ways to address it:
(Recommended) Use regular expression syntax supported by grep(1). Modern grep(1) supports two forms of POSIX 1003.2 regex syntax: basic (obsolete) REs, and modern REs. Syntax is described in details on re_format(7) and regex(7) man pages which are part of BSD and Linux systems respectively. The GNU grep(1) also supports Perl-compatible REs as provided by the pcre(3) library.
In regex language the tab symbol is usually encoded by
\t
atom. The atom is supported by BSD extended regular expressions (egrep
,grep -E
on BSD compatible system), as well as Perl-compatible REs (pcregrep
, GNUgrep -P
).Both basic regular expressions and Linux extended REs apparently have no support for the
\t
. Please consult UNIX utility man page to know which regex language it supports (hence the difference between sed(1), awk(1), and pcregrep(1) regular expressions).Therefore, on Linux:
$ grep -P '\t' FILE ...
On BSD alike system:
$ egrep '\t' FILE ... $ grep -E '\t' FILE ...
Pass the tab character into pattern. This is straightforward when you edit a script file:
# no tabs for Python please! grep -q ' ' *.py && exit 1
However, when working in an interactive shell you may need to rely on shell and terminal capabilities to type the proper symbol into the line. On most terminals this can be done through
Ctrl
+V
key combination which instructs terminal to treat the next input character literally (theV
is for "verbatim"):$ grep '<Ctrl>+<V><TAB>' FILE ...
Some shells may offer advanced support for command typesetting. Such, in bash(1) words of the form
$'string'
are treated specially:bash$ grep $'\t' FILE ...
Please note though, while being nice in a command line this may produce compatibility issues when the script will be moved to another platform. Also, be careful with quotes when using the specials, please consult bash(1) for details.
For Bourne shell (and not only) the same behaviour may be emulated using command substitution augmented by printf(1) to construct proper regex:
$ grep "`printf '\t'`" FILE ...

- 119
- 1
- 3
-
"Modern grep(1) supports two forms of POSIX 1003.2 regex syntax: basic (obsolete) REs, and modern REs." "Syntax is described in details on re_format(7) and regex(7) man pages which are part of BSD and Linux systems respectively." The terms used by POSIX are Basic Regular Expression (BRE) and Extended Regular Expression (ERE). The wording on regex(7) is unfortunate, as BREs are not obsolete at all[1]. POSIX sed for example does not even support EREs. Also, the regex(7) man page does not come from POSIX. [1] https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html – kelvin Apr 01 '21 at 15:17
A good choice is to use sed.
sed -n '/\t/p' file
Examples (works in bash, sh, ksh, csh,..):
[~]$ cat testfile
12 3
1 4 abc
xa c
a c\2
1 23
[~]$ sed -n '/\t/p' testfile
xa c
a c\2
[~]$ sed -n '/\ta\t/p' testfile
a c\2
(This answer has been edited following suggestions in comments. Thank you all)

- 3,782
- 4
- 16
- 33

- 105
- 1
- 3
-
Is there a reason to use `s/pattern/&/p` instead of simply `/PATTERN/p` ? – Pierre-Olivier Vares Oct 01 '21 at 07:57
-
-
This is my personal favorite. It works even in `sed` POSIX mode, needs no bashisms, perl regexes, or `$(printf "…")` workarounds.I'd just recommend to edit the answer so that it's shorter and more to the point (IOW, remove the general explanation of "sed as grep" and just show an example using `'/\t/p'`). – uncleremus Dec 11 '21 at 17:01
use gawk, set the field delimiter to tab (\t) and check for number of fields. If more than 1, then there is/are tabs
awk -F"\t" 'NF>1' file

- 3,782
- 4
- 16
- 33

- 327,991
- 56
- 259
- 343
-
3This is a bit overkill, and misses the question. `awk /\t/` is sufficient for the op's question. – lmat - Reinstate Monica Nov 12 '12 at 16:33
+1 way, that works in ksh, dash, etc: use printf to insert TAB:
grep "$(printf 'BEGIN\tEND')" testfile.txt

- 3,782
- 4
- 16
- 33

- 377
- 1
- 4
- 9
-
This didn't work for me on Ubuntu Trusty (Bash 4.3.11), the following did work though: `grep "$(printf '\t')" testfile.txt` – Josh Rumbut Oct 14 '15 at 18:30
The answer is simpler. Write your grep and within the quote type the tab key, it works well at least in ksh
grep " " *

- 3,782
- 4
- 16
- 33

- 17
- 1
-
5first you need to manage to input a TAB character in your shell - most shells interpret this key as a command (completion) – Kaii Jan 10 '14 at 13:25
This works well for AIX. I am searching for lines containing JOINED<\t>ACTIVE
voradmin cluster status | grep JOINED$'\t'ACTIVE
vorudb201 1 MEMBER(g) JOINED ACTIVE
*vorucaf01 2 SECONDARY JOINED ACTIVE

- 3,782
- 4
- 16
- 33

- 1
Using the 'sed-as-grep' method, but replacing the tabs with a visible character of personal preference is my favourite method, as it clearly shows both which files contain the requested info, and also where it is placed within lines:
sed -n 's/\t/\*\*\*\*/g' file_name
If you wish to make use of line/file info, or other grep options, but also want to see the visible replacement for the tab character, you can achieve this by
grep -[options] -P '\t' file_name | sed 's/\t/\*\*\*\*/g'
As an example:
$ echo "A\tB\nfoo\tbar" > test
$ grep -inH -P '\t' test | sed 's/\t/\*\*\*\*/g'
test:1:A****B
test:2:foo****bar
EDIT: Obviously the above is only useful for viewing file contents to locate tabs --- if the objective is to handle tabs as part of a larger scripting session, this doesn't serve any useful purpose.

- 3,782
- 4
- 16
- 33

- 312
- 1
- 16
You might want to use grep "$(echo -e '\t')"
Only requirement is echo
to be capable of interpretation of backslash escapes.

- 91
- 4
These alternative binary identification methods are totally functional. And, I really like the one's using awk, as I couldn't quite remember the syntaxic use with single binary chars. However, it should also be possible to assign a shell variable a value in a POSIX portable fashion (i.e. TAB=echo "@" | tr "\100" "\011"
), and then employ it from there everywhere, in a POSIX portable fashion; as well (i.e grep "$TAB" filename). While this solution works well with TAB, it will also work well other binary chars, when another desired binary value is used in the assignment (instead of the value for the TAB character to 'tr').

- 1
- 1
The $'\t' notation given in other answers is shell-specific -- it seems to work in bash and zsh but is not universal.
NOTE: The following is for the fish
shell and does not work in bash:
In the fish
shell, one can use an unquoted \t
, for example:
grep \t foo.txt
Or one can use the hex or unicode notations e.g.:
grep \X09 foo.txt
grep \U0009 foo.txt
(these notations are useful for more esoteric characters)
Since these values must be unquoted, one can combine quoted and unquoted values by concatenation:
grep "foo"\t"bar"

- 3,782
- 4
- 16
- 33

- 17,606
- 5
- 95
- 112
You can also use a Perl one-liner instead of grep
resp. grep -P
:
perl -ne 'print if /\t/' FILENAME

- 3,782
- 4
- 16
- 33

- 1,871
- 15
- 28
Build the regex previously, like this:
regex=$'\t'
and then use it:
grep "$regex" file
Other example, with TAB inside the regex:
regex=$'[A-Z][a-z]+\t[A-Z][a-z]+'
echo -e "John\tSmith" | grep -E "$regex"
When we want to use variables in the regex, build it by concatenating the strings without spaces:
first="[A-Z][a-z]+"
last="[A-Z][a-z]+"
regex="$first"'\t'"$last"
echo -e "John\tSmith" | grep -E "$regex"
[RECOMMENDED] This means we can define a TAB variable and write clear code to ease future debugging:
#-- build REGEX to find name parts
TAB=$'\t'
firstname="[A-Z][a-z]+"
surname="[A-Z][a-z]+"
nameregex="${firstname}${TAB}${surname}"
#-- test for person name
echo -e "John\tSmith" | grep -E "$nameregex"
Tested with Bash versions 3.0, 4.2 and 5.1.

- 3,782
- 4
- 16
- 33

- 320
- 4
- 6
You can type
grep \t foo
or
grep '\t' foo
to search for the tab character in the file foo. You can probably also do other escape codes, though I've only tested \n. Although it's rather time-consuming, and unclear why you would want to, in zsh you can also type the tab character, back to the begin, grep and enclose the tab with quotes.

- 3,782
- 4
- 16
- 33

- 349
- 2
- 5
Look for blank spaces many times [[:space:]]*
grep [[:space:]]*'.''.'
Will find something like this:
'the tab' ..
These are single quotations ('), and not double (").
This is how you make concatenation in grep. =-)

- 11
- 1