Answers.Body: <p>The three <code>#</code> are used for splitting group of features that belong together, e.g. a transcript and it's exons. Sometimes you see with a blank line instead of the <code>#</code>.</p>
  
  <p>To <code>grep</code> just the header, which has 1 or 2 <code>#</code> from the line start on, you can use extended regular expression:</p>
  
  <pre><code>$ grep -E "^#{1,2}[^#]" Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>Which means: "grep all lines that started with 1 or 2 <code>#</code> and are not followed by <code>#</code>"</p>
  
  <p>If you like to create a new <code>gff3</code> to get rid of this separator lines you can do this:</p>
  
  <pre><code>$ grep -v "^###" Caenorhabditis_elegans.WBcel235.95.gff3 
  </code></pre>
  
  <p>The <code>-v</code> prints all line that doesn't match the pattern. (I guess this is what @Michael mean by "negator")</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T15:49:02.453Z
Answers.Text: I know "negator" is made up ... The technical term is "negation operator", (https://en.wikipedia.org/wiki/Negation). awk is more powerful than sed, as finswimmer demonstrates. ... original post edited
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-22T15:48:39.303Z
Answers.Text: I discussed with  @terdon. I didn't realise sed/grep had negation operator [^#], I thought this was regex such as Perl..  ... so .... grep "^#.[^#]" ./Caenorhabditis_elegans.WBcel235.95.gff3  ... is another solution
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T07:53:52.353Z
Answers.LastActivityDate: 2019-02-21T07:53:52.353Z
Answers.UserDisplayName: finswimmer
Answers.Body: <p>As others have stated, those are just there to separate the entries for easier parsing. They enable you to do nifty tricks like:</p>
  
  <pre><code>$ awk -v RF='###' '/Y74C9A.3/' Caenorhabditis_elegans.WBcel235.95.gff3 
  I   WormBase    mRNA    4116    10230   .   -   .   ID=transcript:Y74C9A.3;Parent=gene:WBGene00022277;Name=Y74C9A.3;biotype=protein_coding;transcript_id=Y74C9A.3
  I   WormBase    three_prime_UTR 4116    4220    .   -   .   Parent=transcript:Y74C9A.3
  I   WormBase    exon    4116    4358    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e5;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Y74C9A.3.e5;rank=5;version=1
  I   WormBase    CDS 4221    4358    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    5195    5296    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e4;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e4;rank=4;version=1
  I   WormBase    CDS 5195    5296    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    6037    6327    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e3;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e3;rank=3;version=1
  I   WormBase    CDS 6037    6327    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    9727    9846    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e2;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e2;rank=2;version=1
  I   WormBase    CDS 9727    9846    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    CDS 10095   10148   .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    10095   10230   .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e1;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Y74C9A.3.e1;rank=1;version=1
  I   WormBase    five_prime_UTR  10149   10230   .   -   .   Parent=transcript:Y74C9A.3
  </code></pre>
  
  <p>To extract the headers, you just need the lines that start with exactly 2 <code>#</code>:</p>
  
  <pre><code>$ grep '^##[^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  </code></pre>
  
  <p>Or, to also include the comments, lines that start with a <code>#</code>, then either a <code>#</code> or a <code>!</code> and then a non-<code>#</code>:</p>
  
  <pre><code>$ grep '^#[#!][^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  #!genome-build WormBase WBcel235
  #!genome-version WBcel235
  #!genome-date 2012-12
  #!genome-build-accession NCBI:GCA_000002985.3
  #!genebuild-last-updated 2017-06
  </code></pre>
  
  <p>Or just a <code>#</code>, any character and then a non<code>-#</code>:</p>
  
  <pre><code>$ grep '^#.[^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  #!genome-build WormBase WBcel235
  #!genome-version WBcel235
  #!genome-date 2012-12
  #!genome-build-accession NCBI:GCA_000002985.3
  #!genebuild-last-updated 2017-06
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T12:37:29.353Z
Answers.Text: @charlesdarwin it prints the output I show in my answer :) Basically, it sets the string `###` as the record ("line") separator and then print the record that matches `Y74C9A.3`. The default action when something evaluates to true in `awk` is to print the line. So, `/Y74C9A.3/` will be true on lines that contain `Y74C9A.3`, and since we have used `###` as the line separator (record separator) it will print the entire entry for `Y74C9A.3`.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T17:46:23.707Z
Answers.Text: @charlesdarwin why did you add the space after the `-v`? Do you know of an `awk` implementation that requires it? I fear that makes it look like a "verbose" flag.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T21:24:53.610Z
Answers.Text: my awk complained without the space. awk: invalid -v option. I am on macOS X high sierra. using awk version 20070501. crazy number there! is it a date?
Answers.UserDisplayName: Biomagician
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T21:27:30.867Z
Answers.Text: @charlesdarwin ah, yes, I tested on GNU awk. Thanks! And yes, that looks like the 1st of May, 2007.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T09:27:35.827Z
Answers.LastActivityDate: 2019-02-21T12:22:35.550Z
Answers.LastEditDate: 2019-02-21T12:22:35.550Z
Answers.UserDisplayName: terdon
Answers.Body: <p>Hmmm, I dunno. If I was doing this I'd want an easy way to parse the file and ### would be a good marker. Anyway just pop a space character after the #. Using sed ...</p>
  
  <pre><code>sed -n '/^# /p' &lt; ./Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>That should remove the ### lines</p>
  
  <p>Also <code>head -20</code> and <code>sed -n '/1,20/p' ./Caenorhabditis_elegans.WBcel235.95.gff3</code> would get around the problem with a bit of tweaking.</p>
  
  <hr>
  
  <p>The grep verion is (removing unnecessary jargon)</p>
  
  <pre><code>grep '^# ' Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>This is the same command,</p>
  
  <pre><code>grep '^#\s' Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>The point behind the code is there is no negation operator, in sed (I assume grep is the same). In Perl you would simple [^#]{3} (need checking) in your regex (remove all ###). In sed (or grep) you can exclude them using the ^ (beginning of a line) and suffixed with a "space" with only a single character in the middle all 3 letter patterns are removed.</p>
  
  <hr>
  
  <p>Another approach without the space character is </p>
  
  <pre><code>sed -n '/^###/d; /^#/p' ./Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>Albeit this may require,</p>
  
  <pre><code>sed -i '/^###/d; /^#/p' ./file
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-20T23:48:10.773Z
Answers.Text: what is your sed command doing? There is no output and no change to the file when I run it.
Answers.UserDisplayName: Biomagician
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T00:02:36.533Z
Answers.Text: I've edited the post to include the command for your grep approach and included an explanation. It is worth learning sed BTW, it has some nice tricks, but it is not as important as awk.
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T09:31:18.823Z
Answers.Text: Your `sed` command does nothing. I think you meant to use `-i` there, but I don't really see how. There are no lines matching `^# ` in the file. To remove the `###` lines, you would want something like `sed -i '/^###/d' file.gff`. And you can negate character classes in both sed and grep just as you do in perl: `[^#]` means "not #". This is a general regex feature available in all common regex flavors. It isn't a PCRE thing (although GNU grep can deal with PCRE as well, just use the `-P` flag). But note that `[^###]` does not mean "not ###", it just means "not #".
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T15:50:07.293Z
Answers.Text: sed -i '/^###/d' would not work BTW, becaue sed -n '/^###/d' does not. sed '/^###/d' is an improvement. One way to get it working would be >sed -n '/^##/d; /^#/p' ./file ... I've edited the post accordingly
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T16:20:07.457Z
Answers.Text: I suspect sed -n has been deprecated with implementations of sed -i ... sed -n is discussed here https://stackoverflow.com/questions/6255796/how-the-n-command-works-in-sed … ...... It appears sed -i is not supported in all sed implementations, https://stackoverflow.com/questions/18527365/what-does-sed-i-option-do .... SED (-n): is direct from O'Reilly's famous "sed & awk" Doughty & Robbins, e.g p71 ... sed -n works on OS X and Susie [bash and tcsh]. PERL: [^###] is identical to [^#] but [^#]{3} I think would resolve the issue.
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T17:56:24.250Z
Answers.Text: No, `sed -n` is in no way deprecated, it's [defined by POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html).  And it has nothing to do with `-i` ("make the changes in the original file"), `-n` means "don't print unless I tell you to". And `-i` it is supported (with minor format differences) in all `sed` implementations you are likely to use as a bionformatician (GNU sed on Linux, BSD sed on BSD and OSX, even busybox sed on embedded systems). Anyway, `sed -i '/^###/d' ` works just fine, try it out! It's just that it edits the original file, so you don't see any output.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T17:57:19.310Z
Answers.Text: By the way,  `sed -n '/^###/d'` also "works", it just doesn't do anything useful. That means "delete lines starting with `###` but in any case, don't ever print anything". Perhaps you meant something like `sed -n '/^###/!p'`.
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T18:33:31.993Z
Answers.Text: There must by different versions of sed. I do not have any negation operators on mine - this was always my understanding of its weakness, ie your '/^###/!p'. I do agree your /^###/d' can be stacked into a /^#/p command and act as a work-around for negation, which I'd never thought about.
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T18:35:41.670Z
Answers.Text: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/90050/discussion-between-terdon-and-michael-g).
Answers.UserDisplayName: terdon
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-20T22:22:52.310Z
Answers.LastActivityDate: 2019-02-21T15:44:41.507Z
Answers.LastEditDate: 2019-02-21T15:44:41.507Z
Answers.UserDisplayName: M__
Answers.Body: <p>There are some good answers so far, but I don't think any of them fully communicate the significance of the <code>###</code> directive. The <a href="https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md" rel="nofollow noreferrer">GFF3 specification</a> states:</p>
  
  <blockquote>
    <p><em>This directive (three <code>#</code> signs in a row) indicates that all forward references to feature IDs that have been seen to this point have been resolved. After seeing this directive, a program that is processing the file serially can close off any open objects that it has created and return them, thereby allowing iterative access to the file. Otherwise, software cannot know that a feature has been fully populated by its subfeatures until the end of the file has been reached. It is recommended that complex features, such as the canonical gene, be terminated with the <code>###</code> notation.</em></p>
  </blockquote>
  
  <p>In other words, without the <code>###</code> directive you have to load the entire GFF3 file into memory to make sure you've inferred all feature relationships completely (as encoded by <code>ID</code> and <code>Parent</code> attributes). With the <code>###</code> directive, it's possible to process the annotations in smaller chunks, with a MUCH smaller peak memory usage.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T17:04:02.757Z
Answers.Text: So, you don't want to get rid of them and process the file as a single object.
Answers.UserDisplayName: M__
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T17:42:25.043Z
Answers.Text: @MichaelG Right-o! Note, that having `###` directives only makes it *possible* to process GFF3 files efficiently. It is not a guarantee that any particular tool will utilize these directives.
Answers.UserDisplayName: Daniel Standage
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-21T16:28:00.800Z
Answers.LastActivityDate: 2020-04-25T21:18:43.537Z
Answers.LastEditDate: 2020-04-25T21:18:43.537Z
Answers.UserDisplayName: Daniel Standage
Body: <p>I downloaded the annotation of the <em>C. elegans</em> genome in GFF3 format from <a href="ftp://ftp.ensembl.org/pub/release-95/gff3/caenorhabditis_elegans/Caenorhabditis_elegans.WBcel235.95.gff3.gz" rel="nofollow noreferrer">Ensembl</a>.
  I typed the following command, hoping to get the header of the file (lines starting with <code>#</code>).</p>
  
  <pre><code>grep '^#' Caenorhabditis_elegans.WBcel235.95.gff3
  </code></pre>
  
  <p>This returned 46798 lines, many many more than the dozen or so header lines. After searching the file for the <code>#</code> character, I noticed many lines that contain only three hashtag (<code>#</code>) symbols. </p>
  
  <p><a href="https://i.sstatic.net/qWbuD.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/qWbuD.png" alt="screenshot showing hashtags in GFF3 file"></a></p>
  
  <p>Why are these lines there?</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-02-20T23:00:10.243Z
Comments.Text: Could you provide the lines and the context around the lines?
Comments.UserDisplayName: Bioathlete
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-02-20T23:45:32.843Z
Comments.Text: I added a screenshot. There are too many lines to show them all here. There is no constant interval between the ### lines.
Comments.UserDisplayName: Biomagician
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2019-02-21T09:12:10.730Z
Comments.Text: Next time, please don't post images of text. Just copy the text directly into your question and use the [formatting tools](https://bioinformatics.stackexchange.com/help/formatting). images are harder to search, make the page heavier to load (important for users with slow connection) and cannot be copied (I can't extract your file to demonstrate a command that solves your problem).
Comments.UserDisplayName: terdon
Tags: <ensembl><sequence-annotation><gff3><gff>
Title: Purpose of ### (3 consecutive pound signs / hashtags / octothorps) in GFF3
ThreadText: # Purpose of ### (3 consecutive pound signs / hashtags / octothorps) in GFF3
  
  (Asked by: username_0 on 2019-02-20)
  
  I downloaded the annotation of the *C. elegans* genome in GFF3 format from [Ensembl](ftp://ftp.ensembl.org/pub/release-95/gff3/caenorhabditis_elegans/Caenorhabditis_elegans.WBcel235.95.gff3.gz).
  I typed the following command, hoping to get the header of the file (lines starting with `#`).
  
  ```
  grep '^#' Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  This returned 46798 lines, many many more than the dozen or so header lines. After searching the file for the `#` character, I noticed many lines that contain only three hashtag (`#`) symbols.
  
  [![screenshot showing hashtags in GFF3 file](https://i.sstatic.net/qWbuD.png)](https://i.sstatic.net/qWbuD.png)
  
  Why are these lines there?
  
  **Tags:** ensembl, sequence-annotation, gff3, gff
  
  > **Comments:**
  > **username_1**: Could you provide the lines and the context around the lines?  
  > **username_0**: I added a screenshot. There are too many lines to show them all here. There is no constant interval between the ### lines.  
  > **username_2**: Next time, please don't post images of text. Just copy the text directly into your question and use the [formatting tools](https://bioinformatics.stackexchange.com/help/formatting). images are harder to search, make the page heavier to load (important for users with slow connection) and cannot be copied (I can't extract your file to demonstrate a command that solves your problem).  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_5 on 2019-02-21. Score: 4 | Accepted answer
  
  There are some good answers so far, but I don't think any of them fully communicate the significance of the `###` directive. The [GFF3 specification](https://github.com/The-Sequence-Ontology/Specifications/blob/master/gff3.md) states:
  
  > *This directive (three `#` signs in a row) indicates that all forward references to feature IDs that have been seen to this point have been resolved. After seeing this directive, a program that is processing the file serially can close off any open objects that it has created and return them, thereby allowing iterative access to the file. Otherwise, software cannot know that a feature has been fully populated by its subfeatures until the end of the file has been reached. It is recommended that complex features, such as the canonical gene, be terminated with the `###` notation.*
  
  In other words, without the `###` directive you have to load the entire GFF3 file into memory to make sure you've inferred all feature relationships completely (as encoded by `ID` and `Parent` attributes). With the `###` directive, it's possible to process the annotations in smaller chunks, with a MUCH smaller peak memory usage.
  
  > **Comments:**
  > **username_4**: So, you don't want to get rid of them and process the file as a single object.  
  > **username_5**: @MichaelG Right-o! Note, that having `###` directives only makes it *possible* to process GFF3 files efficiently. It is not a guarantee that any particular tool will utilize these directives.  
  
  ---
  
  ### Answer by username_3 on 2019-02-21. Score: 4
  
  The three `#` are used for splitting group of features that belong together, e.g. a transcript and it's exons. Sometimes you see with a blank line instead of the `#`.
  
  To `grep` just the header, which has 1 or 2 `#` from the line start on, you can use extended regular expression:
  
  ```
  $ grep -E "^#{1,2}[^#]" Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  Which means: "grep all lines that started with 1 or 2 `#` and are not followed by `#`"
  
  If you like to create a new `gff3` to get rid of this separator lines you can do this:
  
  ```
  $ grep -v "^###" Caenorhabditis_elegans.WBcel235.95.gff3 
  
  ```
  
  The `-v` prints all line that doesn't match the pattern. (I guess this is what @Michael mean by "negator")
  
  > **Comments:**
  > **username_4**: I know "negator" is made up ... The technical term is "negation operator", (https://en.wikipedia.org/wiki/Negation). awk is more powerful than sed, as username_3 demonstrates. ... original post edited  
  > **username_4**: I discussed with  @username_2. I didn't realise sed/grep had negation operator [^#], I thought this was regex such as Perl..  ... so .... grep "^#.[^#]" ./Caenorhabditis_elegans.WBcel235.95.gff3  ... is another solution  
  
  ---
  
  ### Answer by username_2 on 2019-02-21. Score: 3
  
  As others have stated, those are just there to separate the entries for easier parsing. They enable you to do nifty tricks like:
  
  ```
  $ awk -v RF='###' '/Y74C9A.3/' Caenorhabditis_elegans.WBcel235.95.gff3 
  I   WormBase    mRNA    4116    10230   .   -   .   ID=transcript:Y74C9A.3;Parent=gene:WBGene00022277;Name=Y74C9A.3;biotype=protein_coding;transcript_id=Y74C9A.3
  I   WormBase    three_prime_UTR 4116    4220    .   -   .   Parent=transcript:Y74C9A.3
  I   WormBase    exon    4116    4358    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e5;constitutive=1;ensembl_end_phase=-1;ensembl_phase=0;exon_id=Y74C9A.3.e5;rank=5;version=1
  I   WormBase    CDS 4221    4358    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    5195    5296    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e4;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e4;rank=4;version=1
  I   WormBase    CDS 5195    5296    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    6037    6327    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e3;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e3;rank=3;version=1
  I   WormBase    CDS 6037    6327    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    9727    9846    .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e2;constitutive=1;ensembl_end_phase=0;ensembl_phase=0;exon_id=Y74C9A.3.e2;rank=2;version=1
  I   WormBase    CDS 9727    9846    .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    CDS 10095   10148   .   -   0   ID=CDS:Y74C9A.3;Parent=transcript:Y74C9A.3;protein_id=Y74C9A.3
  I   WormBase    exon    10095   10230   .   -   .   Parent=transcript:Y74C9A.3;Name=Y74C9A.3.e1;constitutive=1;ensembl_end_phase=0;ensembl_phase=-1;exon_id=Y74C9A.3.e1;rank=1;version=1
  I   WormBase    five_prime_UTR  10149   10230   .   -   .   Parent=transcript:Y74C9A.3
  
  ```
  
  To extract the headers, you just need the lines that start with exactly 2 `#`:
  
  ```
  $ grep '^##[^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  
  ```
  
  Or, to also include the comments, lines that start with a `#`, then either a `#` or a `!` and then a non-`#`:
  
  ```
  $ grep '^#[#!][^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  #!genome-build WormBase WBcel235
  #!genome-version WBcel235
  #!genome-date 2012-12
  #!genome-build-accession NCBI:GCA_000002985.3
  #!genebuild-last-updated 2017-06
  
  ```
  
  Or just a `#`, any character and then a non`-#`:
  
  ```
  $ grep '^#.[^#]' Caenorhabditis_elegans.WBcel235.95.gff3 
  ##gff-version 3
  ##sequence-region   I 1 15072434
  ##sequence-region   II 1 15279421
  ##sequence-region   III 1 13783801
  ##sequence-region   IV 1 17493829
  ##sequence-region   MtDNA 1 13794
  ##sequence-region   V 1 20924180
  ##sequence-region   X 1 17718942
  #!genome-build WormBase WBcel235
  #!genome-version WBcel235
  #!genome-date 2012-12
  #!genome-build-accession NCBI:GCA_000002985.3
  #!genebuild-last-updated 2017-06
  
  ```
  
  > **Comments:**
  > **username_2**: @charlesdarwin it prints the output I show in my answer :) Basically, it sets the string `###` as the record ("line") separator and then print the record that matches `Y74C9A.3`. The default action when something evaluates to true in `awk` is to print the line. So, `/Y74C9A.3/` will be true on lines that contain `Y74C9A.3`, and since we have used `###` as the line separator (record separator) it will print the entire entry for `Y74C9A.3`.  
  > **username_2**: @charlesdarwin why did you add the space after the `-v`? Do you know of an `awk` implementation that requires it? I fear that makes it look like a "verbose" flag.  
  > **username_0**: my awk complained without the space. awk: invalid -v option. I am on macOS X high sierra. using awk version 20070501. crazy number there! is it a date?  
  > **username_2**: @charlesdarwin ah, yes, I tested on GNU awk. Thanks! And yes, that looks like the 1st of May, 2007.  
  
  ---
  
  ### Answer by username_4 on 2019-02-20. Score: -1
  
  Hmmm, I dunno. If I was doing this I'd want an easy way to parse the file and ### would be a good marker. Anyway just pop a space character after the #. Using sed ...
  
  ```
  sed -n '/^# /p' < ./Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  That should remove the ### lines
  
  Also `head -20` and `sed -n '/1,20/p' ./Caenorhabditis_elegans.WBcel235.95.gff3` would get around the problem with a bit of tweaking.
  
  ---
  
  The grep verion is (removing unnecessary jargon)
  
  ```
  grep '^# ' Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  This is the same command,
  
  ```
  grep '^#\s' Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  The point behind the code is there is no negation operator, in sed (I assume grep is the same). In Perl you would simple [^#]{3} (need checking) in your regex (remove all ###). In sed (or grep) you can exclude them using the ^ (beginning of a line) and suffixed with a "space" with only a single character in the middle all 3 letter patterns are removed.
  
  ---
  
  Another approach without the space character is
  
  ```
  sed -n '/^###/d; /^#/p' ./Caenorhabditis_elegans.WBcel235.95.gff3
  
  ```
  
  Albeit this may require,
  
  ```
  sed -i '/^###/d; /^#/p' ./file
  
  ```
  
  > **Comments:**
  > **username_0**: what is your sed command doing? There is no output and no change to the file when I run it.  
  > **username_4**: I've edited the post to include the command for your grep approach and included an explanation. It is worth learning sed BTW, it has some nice tricks, but it is not as important as awk.  
  > **username_2**: Your `sed` command does nothing. I think you meant to use `-i` there, but I don't really see how. There are no lines matching `^# ` in the file. To remove the `###` lines, you would want something like `sed -i '/^###/d' file.gff`. And you can negate character classes in both sed and grep just as you do in perl: `[^#]` means "not #". This is a general regex feature available in all common regex flavors. It isn't a PCRE thing (although GNU grep can deal with PCRE as well, just use the `-P` flag). But note that `[^###]` does not mean "not ###", it just means "not #".  
  > **username_4**: sed -i '/^###/d' would not work BTW, becaue sed -n '/^###/d' does not. sed '/^###/d' is an improvement. One way to get it working would be >sed -n '/^##/d; /^#/p' ./file ... I've edited the post accordingly  
  > **username_4**: I suspect sed -n has been deprecated with implementations of sed -i ... sed -n is discussed here https://stackoverflow.com/questions/6255796/how-the-n-command-works-in-sed … ...... It appears sed -i is not supported in all sed implementations, https://stackoverflow.com/questions/18527365/what-does-sed-i-option-do .... SED (-n): is direct from O'Reilly's famous "sed & awk" Doughty & Robbins, e.g p71 ... sed -n works on OS X and Susie [bash and tcsh]. PERL: [^###] is identical to [^#] but [^#]{3} I think would resolve the issue.  
  > **username_2**: No, `sed -n` is in no way deprecated, it's [defined by POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html).  And it has nothing to do with `-i` ("make the changes in the original file"), `-n` means "don't print unless I tell you to". And `-i` it is supported (with minor format differences) in all `sed` implementations you are likely to use as a bionformatician (GNU sed on Linux, BSD sed on BSD and OSX, even busybox sed on embedded systems). Anyway, `sed -i '/^###/d' ` works just fine, try it out! It's just that it edits the original file, so you don't see any output.  
  > **username_2**: By the way,  `sed -n '/^###/d'` also "works", it just doesn't do anything useful. That means "delete lines starting with `###` but in any case, don't ever print anything". Perhaps you meant something like `sed -n '/^###/!p'`.  
  > **username_4**: There must by different versions of sed. I do not have any negation operators on mine - this was always my understanding of its weakness, ie your '/^###/!p'. I do agree your /^###/d' can be stacked into a /^#/p command and act as a work-around for negation, which I'd never thought about.  
  > **username_2**: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/90050/discussion-between-username_2-and-michael-g).  
  
  ---
  
  