I have a tab-tabulated file. I would like to check if every line has the same number of tabs.

For first step, I'd like to print the number of tabs for each individual line.

I've tried grep -o '\t' infile | wc -l, but my implementation of grep says grep: invalid option -- o. Is there an other way?

Nice to have: if possible, due personal preference, I'd prefer to do this with util (grep, cat, etc.) tools, preferably not awk or bash scripting.

  • 1
    The -o option for grep is not POSIX. What OS are you on? – jordanm Nov 11 '13 at 15:24
  • @jordanm I'm on ubuntu, however I'm helping out a friend who is using windows with the utils from msysgit that his company has preinstalled. – n611x007 Nov 11 '13 at 15:51
  • 1
    Just so you know, your grep command wouldn't have worked anyway, you should specify \t as $'\t' but anyway, wc -l would give you the total number for the whole file, not for each line. I can't find a way of getting info per line without a minimum of awk/bash/perl etc. – terdon Nov 11 '13 at 16:31
  • 1
    Best way to help your friend is probably not "Here's a nickel, kid. Get yourself a better computer" but if they're going to insist on crippling their toolkit it's the only accurate one. awk 'BEGIN{FS="\t"} NR==1{f=NF} f!=NF { print "tab mismatch at line "NR; exit 1; }' – jthill Nov 11 '13 at 16:37
  • 1
    @naxa it didn't :). Try counting manually, '\t' will count the number of t letters and anyway, wc -l will print the number of lines in total, so in this case, the total number of ts in the file, not the number per line. Try printf 'foo\tbar' | grep -o '\t' | wc and then printf 'foo\tbar' | grep -o $'\t' | wc. – terdon Nov 11 '13 at 16:55

If your goal is only to detect whether there's always the same number of tabs per line (no bash, no awk):

sed 's/[^\t]//g' file | sort -u | wc -l

If it outputs 1, then it's good!

Or, replacing sed with tr:

tr -cd \\t\\n < file | sort -u | wc -l

or if you like useless uses of cats and don't like concatenating options:

cat file | tr -c -d \\t\\n | sort -u | wc -l

The trick is to remove all non-tab characters on each line, and then sort/uniq what remains.

  • 2
    Regarding your tr solution, why not just tr -cd "\t" | wc -c? – Joseph R. Nov 11 '13 at 16:47
  • 1
    @JosephR. Because tr -cd \\t will also remove the newline character, and we want to keep this one! – gniourf_gniourf Nov 11 '13 at 16:51
  • 2
    OK. Got it. I thought tr would respect newline boundaries and produce line-by-line output by default. – Joseph R. Nov 11 '13 at 16:56

I think sed etc. is not suitable for this, an easy way is to call awk with tab as field separator:

printf $'hello\tworld\thugo\nfoo\tbar\nbaz\n' | awk -F$'\t' '{print NF-1;}'

which gives


Honestly, the easiest way is to use awk:

awk -F'\t' '{print NF-1}' foo

NF is the number of fields, -F'\t' tells awk to split fields on tabs so the number of tabs will be one less than the number of fields which is why we have awk print NF-1.

If you really don't want to use awk you could do (note: this does not count trailing tabs at the end of each line):

$ while read line; do echo "$line" | fold -1 | grep -c $'\t'; done < foo

To deal with leading and trailing tabs as well as with other weird characters (such as backslashes), do this instead:

$ while IFS= read line; do echo "$line" | fold -1 | grep -c $'\t'; done < foo
  • while read lines; do ... ; done < foo : read each line of file foo into the variable $line.
  • echo "$line" | fold -1 : the fold command will print one character per line
  • grep -c $'\t' : this is run on each line of the file ($line) but since $line has been folded into one character per line, grep -c will count the number of tabs in that line. If you don't fold first, grep -c will count the number of matching lines and will not give you a tab count per line.

You could also use Perl of course but I guess that's not available either. Here's one way regardless:

perl -lne '@a=/\t/g;print scalar @a' foo 
  • 1
    Your non-awk solution doesn't quite work with leading/trailing tabs and consecutive tabs. Use while IFS= read line if your shell supports it to fix that. – gniourf_gniourf Nov 11 '13 at 16:34
  • @gniourf_gniourf yes, I know I pointed that out in my answer (see note). Since the OP specifically asked for non bash scripting, I did not want to use things like IFS. – terdon Nov 11 '13 at 16:40
  • 1
    IFS is rather common in shells (not only bash)... so you could mention it in your post ;). – gniourf_gniourf Nov 11 '13 at 16:41
  • 1
    @gniourf_gniourf fair enough, I thought it was a bashism. Any idea if it would be available in the shell the OP's friend is using? If I understand correctly, it is this one and it claims to be a bash shell so I guess IFS would work. By the way, IFS= is not needed for consecutive tabs. – terdon Nov 11 '13 at 16:48
  • 1
    @naxa most utils work on streams of data, not lines. To work on lines, you tend to need things like awk/sed/perl etc. In this case, the Unix way is awk, by far the simplest approach. – terdon Nov 11 '13 at 17:07

I ralize its too late, but the OP's command line was almost correct. He just needed the $ in front of his TAB ('\t')

grep -o $'\t' infile | wc -l

does exaclty what he was after.

  • 1
    OP's problem was different. Their grep didn't support the -o option. – muru Jan 28 '15 at 18:43
  • ah, ok. Still very new to this and wondered why if he was so close to an answer everyone too him away from grep. – tpettinato Jan 28 '15 at 18:45
  • That's fine, I suppose. The comments below the question are informative. terdon points out this, and other mistakes in OP's approach (notably, even this does not do what OP wants, which is counting the number of tabs per line). – muru Jan 28 '15 at 18:50

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.