Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
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. –  naxa Nov 11 '13 at 15:51
    
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
    
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
    
@terdon I think it worked for me, however I edited to use '\t' and tested it on my box. –  naxa Nov 11 '13 at 16:45
show 2 more comments

3 Answers 3

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.

share|improve this answer
2  
Regarding your tr solution, why not just tr -cd "\t" | wc -c? –  Joseph R. Nov 11 '13 at 16:47
    
@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
1  
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
add comment

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

2
1
0
share|improve this answer
add comment

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
2
4
0
1
0

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 
share|improve this answer
    
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
    
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
    
True for consecutive tabs! –  gniourf_gniourf Nov 11 '13 at 16:52
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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