2

I would like to count the number of N characters in the second column of a file and then print this count to the third column. Example input file (tab-separated):

sample1 TCTNG
sample2 CCNGGGGGTN
sample3 GGGNNNTC

Desired output (tab-separated):

sample1 TCTNG   1
sample2 CCNGGGGGTN  2
sample3 GGGNNNTC    3

I can get a messy version doing the following, but I would like a one-liner, preferably in awk.

> awk -F '\t' '{print $2}' file.txt | awk -FN '{print NF-1}' > NCount.txt
> paste -d '\t' file.txt NCount.txt

sample1 TCTNG   
    1
sample2 CCNGGGGGTN  
    2
sample3 GGGNNNTC
    3
2
  • What do you want to happen if a line's column 2 contains no Ns ? Commented Sep 23, 2021 at 8:14
  • 1
    Some of the output lines (but not all) listed as output from the messy version contain trailing TABs (the listed input file also contains TABs between the columns). Is that intentional? Is it a consequence of trailing TABs in the input file? Can you clarify? Preferably by editing (changing) your question, not here in comments (without "Edit:", "Update:", or similar - the question should appear as if it was written today). Commented Sep 23, 2021 at 11:17

3 Answers 3

9
awk 'BEGIN{FS=OFS="\t"} {print $0, gsub(/N/,"",$2)}' file
sample1 TCTNG   1
sample2 CCNGGGGGTN  2
sample3 GGGNNNTC    3

Based on : How to print the count of pattern at each line?

0
7

The gsub() function returns the number of made substitutions. You may use this fact to count the number of N characters in the 2nd field and to add this number as a new field on each line:

$ awk -F '\t' '{ $3 = gsub("N","N",$2) }; 1' file
sample1 TCTNG 1
sample2 CCNGGGGGTN 2
sample3 GGGNNNTC 3

The output is caused by the trailing 1 (it is equivalent to using { print } or { print $0 }).

Set the value of the special variable OFS to use another field delimiter than the default (space) in the output. Here I'm using whatever the input field delimiter is set to:

$ awk -F '\t' 'BEGIN { OFS=FS } { $3 = gsub("N","N",$2) }; 1' file
sample1 TCTNG   1
sample2 CCNGGGGGTN      2
sample3 GGGNNNTC        3

Simirlarly in Perl, but using the tr operator in place of gsub():

$ perl -MEnglish -a -F '\t' -e 'BEGIN { $OFS="\t"; $ORS="\n" } print @F, ($F[1] =~ tr/N/N/)' file
sample1 TCTNG   1
sample2 CCNGGGGGTN      2
sample3 GGGNNNTC        3
3
  • I am having issues with a newline between the 2nd and 3rd columns, making the count in the 3rd column appear on the next line (as in the "messy" version I shared in the original post). Could this have something to do with an invisible newline character after the 2nd column?
    – eam12
    Commented Sep 22, 2021 at 19:55
  • @eam12 I can't really reproduce what you're seeing. I can get quite funky results by converting the input to a DOS-formatted text file, but not really so that the count appears on a new line by itself. Make sure that your data is a Unix text file.
    – Kusalananda
    Commented Sep 22, 2021 at 20:01
  • Hmmm. It's a BLAST output file that was created in Unix. I'll look into it more. Must be something strange on my end. Thank you!
    – eam12
    Commented Sep 22, 2021 at 20:13
2

Using Raku (formerly known as Perl_6)

raku -ne 'put ~$/.join("").chars if m:g/N*/;'  

Sample Input:

sample0 TCTG
sample1 TCTNG
sample2 CCNGGGGGTN
sample3 GGGNNNTC

Sample Output:

sample0 TCTG    0
sample1 TCTNG   1
sample2 CCNGGGGGTN  2
sample3 GGGNNNTC    3

Above code: print the Raku $_ topic variable first (followed by a \t), then print a count of the the join("") -concatenated N matches, and add as a new column to the end of each line.

https://raku.org

You must log in to answer this question.

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