I have a text file, and I want extract the string from each line coming after "OS="

input file line
A0A0A9PBI3_ARUDO Uncharacterized protein OS=Arundo donax OX=35708 PE=4 SV=1
K3Y356_SETIT ATP-dependent DNA helicase OS=Setaria italica OX=4555 PE=3 SV=1

Output desired

OS=Arundo donax
OS=Setaria italica


Arundo donax
Setaria italica
  • Are there always 2 words to print after OS= or do you want all words between OS= and OX=?
    – oliv
    Sep 5, 2019 at 14:13
  • i need only two words
    – shahzad
    Sep 5, 2019 at 14:17
  • 3
    This is a work order, not a question. No demonstrated effort. Sep 6, 2019 at 8:25

4 Answers 4


Use GNU grep (or compatible) with extended regex:

grep -Eo "OS=\w+ \w+" file

or basic regex (you need to escape +

grep -o "OS=\w\+ \w\+" file
# or
grep -o "OS=\w* \w*" file

To get everything from OS= up to OX= you can use grep with perl-compatible regex (PCRE) (-P option) if available and make lookahead:

grep -Po "OS=.*(?=OX=)" file

#to also leave out "OS="
#use lookbehind
grep -Po "(?<=OS=).*(?=OX=)" file
#or Keep-out \K
grep -Po "OS=\K.*(?=OX=)" file

or use grep including OX= and remove it with sed afterwards:

grep -o "OS=.*\( OX=\)" file | sed 's/ OX=$//'


OS=Arundo donax
OS=Setaria italica

In Perl, two non-whitespace "words":

$ perl -lne 'print $1 if /OS=(\S+ \S+)/' input

or everything up to OX=:

$ perl -lne 'print $1 if /OS=(.*?) OX=/' input 

or everything up to the next something=:

$ perl -lne 'print $1 if /OS=(.*?) (\w+)=/' input

With your sample input, they all give the same output, but the output would be different with e.g. an input like this:

ABC=something here OS=foo bar doo PE=3 OX=1234

A more robust way is to use sed to parse the full value until the word containing the next = is found. That way it will work on any sized value (e.g. if you have a font with one word or three words).

sed 's/.*OS=\([^=]*\).*/\1/;s/ [^ ]*$//'

The first block grabs everything up to OS=, the second block in the capture group (denoted by \(\)'s) matches upto the next = and can be referred to in the replacement as \1. The next substitution rids the last word which is a fragment from the next assignment.

Note: the ^ in []'s is to exclude match the character in this case everything that is not an = sign.

awk '{print $(NF-4), $(NF-3)}' file

OS=Arundo donax
OS=Setaria italica 


awk -F= '{sub(/OX/,""); print $(NF-3)}' file 

Arundo donax 
Setaria italica

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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