11

I have a file of genomic data with tag counts, I want to know how many are represented once:

$ grep "^1" file |wc -l

includes all lines beginning with 1, so it includes tags represented 10 times, 11, times, 100 times, 1245 times, etc. How do I do this?

Current format
79      TGCAG.....
1       TGCAG.....
1257    TGCAG.....
1       TGCAG......

I only want the lines that are:

1       TGCAG.....

So it cannot include the lines beginning with 1257. NOTE: The file above is tab delimited.

2
  • 2
    By the way, based on you example here, you might be interested in our sister site, Bioinformatics.
    – terdon
    Jul 28, 2018 at 16:39
  • I have erred on the side of retracting my own close vote, because the answers on the linked question which most convince me, are those which anticipate the possibility of -, and the current such answers either require PCRE (which is not required here), or assume ASCII space character as a delimiter, not a tab character.
    – sourcejedi
    Jul 30, 2018 at 13:33

7 Answers 7

27

The question in the body

Select lines that start with a 1 and are followed by an space

grep -c '^1\s'          file
grep -c '^1[[:space:]]' file

That will also give the count of lines (without needing the call to wc)

The question in the title

A 1 not followed by another number (or nothing):

grep -cE '^1([^0-9]|$)' file 

But both solutions above have some interesting issues, keep reading.


In the body of the question the user claim that the file is "tab delimited".

Delimiter

tab

A line starting with a 1 followed by a tab (an actual tab in the command). This fails if the delimiter is an space (or any other, or none):

grep '^1    ' file

space

A line starting with a 1 followed by a space (an actual space in the command). This fails if the delimiter is any other or none.:

grep '^1 ' file

tab or space

grep '^1(   | )' file
grep '^1[[:blank:]]' file

whitespace

A more flexible option is to include several space (horizontal and vertical) characters. The [:space:] character class set is composed of (space), \t (horizontal tab), \r (carriage return),\n(newline), \v (vertical tab) and \f (form feed). But grep can not match a newline (it is an internal limitation that could only be avoided with the -z option). It is possible to use it as a description on the delimiter. It is also possible, and shorter, to use the GNU available shorthand of \s:

grep -c '^1[[:space:]]` file
grep -c '^1\s'          file

But this option will fail if the delimiter is something like a colon : or any other punctuation character (or any letter).

Boundary

Or, we can use the transition from a digit to a "not a digit" boundary, well, actually "a character not in [_[:alnum:]] (_a-zA-Z0-9)":

grep -c  '^1\b' file       # portable but not POSIX.
grep -c  '^1\>' file       # portable but not POSIX.
grep -wc '^1'   file       # portable but not POSIX.
grep -c  '^1\W' file       # portable but not POSIX (not match only a `1`) (not underscore in BSD).

This will accept as valid lines that start with a 1 and are followed by some punctuation character.

1
  • There is no way that the lines presented by the user: 1 TGCAG… will contain only a 1 (that is: without genomic data). But, anyway, a viable solution also added. @StéphaneChazelas
    – user232326
    Jul 29, 2018 at 19:20
19

Sounds like you just want this:

$ grep '^1\b' a
1        TGCAG.....
1        TGCAG......

For the counting portion of this:

$ grep -c '^1\b' file
2
0
16

With awk:

awk '$1 == "1" { print; x++ } END { print x, "total matches" }' inputfile
3
  • Nice touch w/ the total!
    – slm
    Jul 27, 2018 at 22:06
  • 3
    Plus can use awk '{print $1}' <inputfile|sort -n|uniq -c get a summary of the tag count frequencies.
    – steve
    Jul 27, 2018 at 22:13
  • No need to indirect inputfile with <, but yes indeed.
    – DopeGhoti
    Jul 27, 2018 at 22:26
14

Either of these will pick out lines with a 1 in the first column

awk '$1 == 1'
grep -w '^1'

These can both can be extended so you don't even need the wc to count the lines

awk '$1==1 { x++ } END { print x }'
grep -cw '^1'
0
4

Using grep:

grep -c '^1\s' file

This will match any line starting with a 1 immediately followed by whitespace and provide a count of those lines (eliminating the need for wc -l)


$ cat input
79       TGCAG.....
1        TGCAG.....
1257     TGCAG.....
1        TGCAG......
$ grep -Ec '^1\s' input
2
0
3

Good answers here, but assuming that not every line ends in a space (like if you've got some that actually make it to your "="), you can use this:

 grep -c "^1[^0-9]" file

It basically matches for any line that begins with one, followed by a non-digit, including white space. A little more verbose, but also more foolproof. (Though it's worth noting that there's nothing here for the null condition of just-one-on-the-line, it isn't end-of-line sensitive.)

1
  • 1
    Note that it disallows lines consisting only of 1. If that's not desired, use e.g. ^1($|[^0-9])
    – OJFord
    Jul 30, 2018 at 13:33
0

You can use below line also:

$ awk -F' ' '{if($1=="1") print $0}' <your file name> | wc -l

The parameter -F makes the field separator a whitespace. If the first field's value is '1', its line will be printed.

Not the answer you're looking for? Browse other questions tagged .