Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I'm trying to get the number of matches (in this case occurrences of { or }) in each line of a .tex file.

I know that the -o flag returns only the match, but it returns each match on a new line, even combined with the -n flag. I don't know of anything I could pipe this through to count the repeats. The -c flag only returns the total number of matches in the entire file - maybe I could pipe one line at a time to grep?

share|improve this question

2 Answers 2

up vote 5 down vote accepted
grep -o -n '[{}]' <filename> | cut -d : -f 1 | uniq -c

The output will be something like:

3 1
1 2

Meaning 3 occurrences in the first line and 1 in the second.

Taken from http://stackoverflow.com/a/15366097/3378354 .

share|improve this answer
    
Thanks - google found lots of regex hits on SU, but not that one on SO, which doesn't even seem to have a regex tag. The sort isn't strictly necessary as grep's output is sorted by line number, but I guess it's good practice before uniq. –  Chris H Jun 16 at 10:45
2  
Probably not tagged regex because the regex is the easy part. –  Tom Zych Jun 16 at 10:51
    
Is it actually necessary to sort -n? Doesn't it come out in line number order anyway? –  Tom Zych Jun 16 at 10:52
    
You are right, sort -n is not necessary. Thanks. –  Moebius Jun 16 at 10:58
    
@TomZych, it turned out you were right, but had I known that I might not have asked. The mental jump from grep to tag:regex was perhaps a bit too much though. –  Chris H Jun 16 at 12:54

Is using grep a requirement?  Here’s an alternative:

sed 's/[^{}]//g' your_file | awk '{print NR, length }'

The sed strips out all characters other than { and } (i.e., leaving only { and } characters), and then the awk counts the characters on each line (which are just the { and } characters).  To suppress lines with no matches,

sed 's/[^{}]//g' your_file | awk '/./ {print NR, length }'

Note that my solution assumes (requires) that the strings you are looking for are single characters.  Moebius’s answer is more easily adapted to multi-character strings.  Also, neither of our answers excludes quoted or escaped occurrences of the characters/strings of interest; e.g.,

{ "nullfunc() {}" }

would be considered to contain four brace characters.

share|improve this answer
    
grep wasn't really a requirement, it was just where I started looking for a solution, because it gave me something close. I've never had a need for awk, so had I not used the answer above I'd have used this as a chance to experiment -- I may still. What I failed to make clear (but it doesn't affect either answer) is that I wanted to run the script once per bracket, to help me track down a mismatch (in LaTeX source, here for a table) where most pairs occur in a single line. –  Chris H Jun 16 at 15:46
    
I’m not quite sure what you mean by “run the script once per bracket,” but if you want to track down a brace mismatch, you might want to try something like sed 's/{[^{}]*}//g' your_file | grep –n '[{}]', where the sed strips out (matched) pairs. If you have nested pairs, use sed 's/{[^{}]*}//g;s/{[^{}]*}//g;s/{[^{}]*}//g;…' …, repeating the s/{[^{}]*}//g as many times as your deepest nesting. –  Scott Jun 16 at 16:41
    
I meant execute `sed 's/[^}]//g' your_file | awk '{print NR, length }' and 's/[^{]//g' your_file | awk '{print NR, length }'. I do indeed have nesting, and working out the deepest level seemed like a chore. Turning many lines into a handful (there are a few cases where the braces only match over multiple lines for valid reasons) worked well (I use jedit which highlights the matching bracket -- for any type of bracket it understands -- so I really did just need to narrow it down). –  Chris H Jun 16 at 17:53

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.