I have a file that looks like that:

chr1    3143567 3143568 .3-2704 1.000000|ENSMUSG00000102693.2
chr1    3143599 3143600 .3-2705 1.000000|ENSMUSG00000102693.2
chr1    3143631 3143632 .3-2706 1.000000|ENSMUSG00000102693.2
chr1    3143663 3143664 .3-2707 1.000000|ENSMUSG00000102693.2
chr1    3143695 3143696 .3-2708 1.000000|ENSMUSG00000102693.2
chr1    3143727 3143728 .3-2709 1.000000|ENSMUSG00000102693.2

I'm writing 2 sed expressions to filter everything before the | first and with result file I discard everything after the . like so:

sed -n -e 's/^.*|//p' original_file.txt > first_result.txt

sed -n -e 's/\..*//p' first_result.txt > final_result.txt

How can I write all of that in one line ?

The end goal is to capture ENSMUSG00000102693


3 Answers 3


Your commands would discard lines containing no | character, and lines where the mouse gene identifier has no version number. I'm not certain this is intended, but it's a side effect of using sed -n with the p flag on the s command. I'm going to assume that this is unintended.

Just use two expressions with sed:

sed -e 's/.*|//' -e 's/\..*//' file >newfile

With a grep command that has the non-standard -o option, and assuming that you just want to extract all Ensembl mouse gene stable IDs from the file (and that the file only contains stable IDs that you'd like to extract),

grep -o 'ENSMUSG[[:digit:]]*' file >newfile

You may also use two chained cut commands, each one doing similar modifications of the data as the two sed substitutions earlier in this answer. Using static cut would probably be quicker than using a regular expression, but I doubt you'd see any major speed differences unless your input data is huge.

cut -d '|' -f 2 file | cut -d '.' -f 1 >newfile
  • you seem to know the data well, working in bioinformatics ? yes i just want the gene stable ID without version number and | since I need to use these IDs to find the human orthologs genes
    – moth
    Oct 20, 2021 at 11:26
  • @moth If you're using the Ensembl Perl API, you might just as well do this parsing operation from Perl instead of as a separate external step. The orthologs would then be fetchable with the Ensembl Compara Perl API, I presume. You may want to ask for the specifics on the bioinformatics SE site.
    – Kusalananda
    Oct 20, 2021 at 11:32

You can use GNU grep (wich seems to have a slightly better performance than sed):

$ grep -Po '(?<=\|)[^|.]+' first_result.txt 

  • The pattern (?<=\|)[^|.]+ means "look for all the characters that are not a | or a . ([^|.]+) starting at (and excluding) the initial | ((?<=\|))".

With sed:

$ sed 's/.*|\([^|]\+\)\..*/\1/' first_result.txt  
  • The pattern .*|\([^|]\+\)\..* means "remove all the characters between | and . (.*|, \..*) and capture what is in between (\([^|]\+\)), finally replace all by the captured pattern (/\1/).

Or more succintly:

$ sed -E 's/.*\|([^|]+)\..*/\1/'

You could use a single sed expression as below. Match everything up to the last | to ignore and then capture the part before the last . and exclude it in the result. On any sed with POSIX BRE support

sed 's/.*|\([^.]*\)\..*/\1/'

If Awk is preferred,

awk -F'[|.]' '{ print $(NF-1) }'
  • 1
    It seems better to use \([^.]\+\). The .* will capture too much and have to backtrack. You want to capture all non-dot characters up to the dot; just say that. Also, there is no reason to backslash-escape the dot inside the character class. Oct 20, 2021 at 19:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.