No grep cannot do this in one pass, I would suggest using awk:
awk -v pat='alfa beta gamma' '
BEGIN { split(pat, p) }
{ for(k in p) if($0 ~ p[k]) c[k]++ }
END { for(k in p) print p[k], c[k]?c[k]:0 }
'
Or as a rather long one-liner:
awk -v pat='alfa beta gamma' 'BEGIN { split(pat, p) } { for(k in p) if($0 ~ p[k]) c[k]++ } END { for(k in p) print p[k], c[k]?c[k]:0 }'
Explanation
pat
is split into the p
array, which is then used to search for matches on each line ($0 ~ p[k]
). The counters are held in the c
array. The c[k]?c[k]:0
bit uses the ternary operator to print 0 when c[k]
is zero.
Note if your pattern contains space, you need to use a different delimiter between the patterns in pat
and to update the split
command accordingly.
Testing
Input:
cat << EOF > file
alfa
beta
gamma
gamma
EOF
Output with pat='alfa beta gamma'
:
alfa 1
beta 1
gamma 2
Input:
cat << EOF > file
alfa beta
beta
gamma gamma
gamma alfa
alfalfa
alfa alfa
EOF
Output with pat='^a a$ alfa beta gamma'
:
beta 2
gamma 2
^a 3
a$ 6
alfa 4
The output matches in both cases the output from running grep -c
with each pattern individually.
sort file | uniq -c
and thengrep
on that? – slhck Jan 8 '13 at 11:24alfax
,alfay
,alfaz
(on separate lines), this script will report1 alfax
/1 alfay
/1 alfaz
rather than3 alfa
. An input line ofalfa beta
(on the same line) will result in a report of1 alfa beta
rather than1 alfa
/1 beta
. – Scott Jan 8 '13 at 18:38