<p>This script is wrong because a quality string may start with <code>@</code>. With bioawk, it can be simplified to:</p>

<pre><code>bioawk -c fastx '{ readlength[length($seq)]++; countread++ } END{...}'
</code></pre>

<p>The <code>END{}</code> block is the same as your original version.</p>

<p>EDIT: forgot <code>-c fastx</code> is the original answer. Thank @MattBashton for pointing this out.</p>

CC BY-SA 4.0
2018-08-20T15:34:51.747Z
Using the exact same END{} code from the OP fails in this example with `bioawk: illegal field $(), name "seq"`
Matt Bashton
CC BY-SA 4.0
2018-08-20T12:03:30.090Z
2018-08-20T15:49:32.900Z
2018-08-20T15:49:32.900Z
user172818
<p>This can also be done with regular awk.</p>

<pre><code>awk '{if(NR%4==2) {count++; bases += length} } END{print bases/count}' &lt;fastq_file&gt;
</code></pre>

<p>The <code>NR%4==2</code> count the second line out of every block of 4.  <code>length</code> is a built-in that defaults to the length of the line, same as <code>length($0)</code>.  In this case you can inject you custom printing to the <code>END{}</code> block but <code>countread</code> and <code>countstored</code> will always be the same since the averaging is done on the fly.</p>

CC BY-SA 4.0
2018-08-20T18:01:08.877Z
Note that, like OP’s code, this will only work on FASTQ files that don’t break the sequence and/or quality string across multiple lines.
Konrad Rudolph
CC BY-SA 4.0
2018-08-20T22:04:37.853Z
That is correct.  However that practice is highly frowned upon so should not be an issue with most FASTQ files
Bioathlete
CC BY-SA 4.0
2018-08-21T09:43:46.737Z
I've yet to ever encounter a FASTQ file which has sequence or quality on multiple lines, I think for all intensive purposes assuming 4 lines per record should be fine.
Matt Bashton
CC BY-SA 4.0
2018-08-20T14:43:26.193Z
2018-08-20T14:43:26.193Z
Bioathlete
<p>I found <a href="http://cagt.bu.edu/w/images/8/81/Avg_read_len_fastq.awk" rel="nofollow noreferrer">here</a> this awk script: </p>

<pre><code>BEGIN {
  headertype="";
  }
{
  if($0 ~ "^@") {
    countread++;
    headertype="@";
  }
  else if($0 ~ "^+") {
    headertype="+";
  }
  else if(headertype="@") { # This is a nuc sequence
    len=length($0);
    if (len&gt;4) {
      readlength[len]++;
    }
  }
}
END {
  for (i in readlength){
    countstored+=readlength[i];
    lensum+=readlength[i]*i;
    print i, readlength[i];
  }
  print "reads read = "countread &gt; "/dev/stderr";
  print "reads stored = "countstored &gt; "/dev/stderr";
  print "read average length = "lensum/countstored &gt; "/dev/stderr";
}
</code></pre>

<p>and I just wonder if it is possible to shorten it with bioawk?</p>

CC BY-SA 4.0
2018-08-19T10:49:32.527Z
It might be possible.  What problem do you have with having a long script? Why do you want a shorter script? Or do you want a faster script?
llrs
CC BY-SA 4.0
2021-12-17T08:37:19.907Z
Did anyone get the correct script for finding out the average read length?
Saraswati Awasthi
<fastq><awk><bioawk>
Calculating read average length in a Fastq file with bioawk/awk
# Calculating read average length in a Fastq file with bioawk/awk

(Asked by: username_0 on 2018-08-18)

I found here this awk script: 
BEGIN {
  headertype="";
  }
{
  if($0 ~ "^@") {
    countread++;
    headertype="@";
  }
  else if($0 ~ "^+") {
    headertype="+";
  }
  else if(headertype="@") { # This is a nuc sequence
    len=length($0);
    if (len>4) {
      readlength[len]++;
    }
  }
}
END {
  for (i in readlength){
    countstored+=readlength[i];
    lensum+=readlength[i]*i;
    print i, readlength[i];
  }
  print "reads read = "countread > "/dev/stderr";
  print "reads stored = "countstored > "/dev/stderr";
  print "read average length = "lensum/countstored > "/dev/stderr";
}

and I just wonder if it is possible to shorten it with bioawk?

**Tags:** fastq, awk, bioawk
> **Comments:**
> **username_1**: It might be possible.  What problem do you have with having a long script? Why do you want a shorter script? Or do you want a faster script?  
> **username_2**: Did anyone get the correct script for finding out the average read length?  

---

## 2 answers

### Answer by username_5 on 2018-08-20. Score: 8 | Accepted answer

This can also be done with regular awk.
awk '{if(NR%4==2) {count++; bases += length} } END{print bases/count}' 

The NR%4==2 count the second line out of every block of 4.  length is a built-in that defaults to the length of the line, same as length($0).  In this case you can inject you custom printing to the END{} block but countread and countstored will always be the same since the averaging is done on the fly.

> **Comments:**
> **username_6**: Note that, like OP’s code, this will only work on FASTQ files that don’t break the sequence and/or quality string across multiple lines.  
> **username_5**: That is correct.  However that practice is highly frowned upon so should not be an issue with most FASTQ files  
> **username_4**: I've yet to ever encounter a FASTQ file which has sequence or quality on multiple lines, I think for all intensive purposes assuming 4 lines per record should be fine.  

---

### Answer by username_3 on 2018-08-20. Score: 3

This script is wrong because a quality string may start with @. With bioawk, it can be simplified to:
bioawk -c fastx '{ readlength[length($seq)]++; countread++ } END{...}'

The END{} block is the same as your original version.
EDIT: forgot -c fastx is the original answer. Thank @MattBashton for pointing this out.

> **Comments:**
> **username_4**: Using the exact same END{} code from the OP fails in this example with `bioawk: illegal field $(), name "seq"`  

---

