Home > other >  Print lines below a header matching a condition
Print lines below a header matching a condition

Time:10-06

I have a database like this:

>2654570298
MRNYSYKGKWEKLLTPEIVKKLTLINEFKGEQRLFIKAHKDELKELSELA
KIQSTEASNKIEGIFTSDDRFKSLAQAKTTPRNRNESEIAGYRDVLNTIH
DSYEYIPISASYFLQLHRDLYKFVAKNDVGKFKSSDNIIRETDEKGNERL
RFRPVPAWETPAAIDELCKAYADAKEEIDPLILNAMFILDFLCIHPFNDG
NGRMSRLLTLLLLYKTGFIVGKYISIEKIIEESKETYYEVLQDSLVGWHE
NENDYKPFVNYMLGVIVNAYKEFESRTELVTNPNLTKSDRIREIIKDHIG
TITKAELLEMNPDISDTTVQRTLAKLLKNNDIKKIGGGRYTKYTWNTEEQ

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570301
MNESELYKELGILTKDKSKWAENIQYVSSLLNHESAKIQAKALWLLGEMG
LEYPDSIQDAVPMVASFCDSENALLRERAVNALGRIGRGNYNLIEPYWSD
LFRFASDDEPKVRLSFIWASENVATNTPDIYENHMSVFESLLHDIDDKVR
MESPEIFRVLGKRRPEFVIPYIEQLQKMAETDSNRVVRIHSLGAIKVTTS
K

>2654570302
MWNMIWPLVLIVGSNCFYNICTKSMPEGTNTFGALTVTYLVGAVLSAVLF
VVSVKPAGVLNEISKINWTSFVLGLVIVGLEAGYVFLYRAGWKVSNGALT
ANICLAIALIVIGFLLYKESISIKQVAGIVVCGFGLFLING

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

I would like to filter it printing only the sequences whose header contains a "|K", either using awk, grep, or anything similar. Desired output:

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

Note that the number of lines between one header and the next are not always the same, and line break always separates one sequence and the following header.

Anyone could help?

CodePudding user response:

Also using awk this can help you:

awk '/^>/ {f=/\|K/} f' file
>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED
  • if f is true, print those lines. By default, in awk when the condition is evaluated to true, the content of $0 is printed.
  • You can see the value of f with a print.
  • and what rows or records are true:
awk '/^>/ {f=/\|K/} f {print NR, f}' file

CodePudding user response:

If you unset the record separator (RS), awk will consider every section as one record, e.g. to find records with |K in them:

awk '/\|K/' RS=

Output:

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI
>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

Now, if you want the output to be dual new-line separated and only match the header, you can change the field separator (FS) and output record separator (ORS), e.g.:

awk '$1 ~ /\|K/' RS= FS='\n' ORS='\n\n'

Output:

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

CodePudding user response:

I would use GNU AWK for this task following way, let file.txt content be

>2654570298
MRNYSYKGKWEKLLTPEIVKKLTLINEFKGEQRLFIKAHKDELKELSELA
KIQSTEASNKIEGIFTSDDRFKSLAQAKTTPRNRNESEIAGYRDVLNTIH
DSYEYIPISASYFLQLHRDLYKFVAKNDVGKFKSSDNIIRETDEKGNERL
RFRPVPAWETPAAIDELCKAYADAKEEIDPLILNAMFILDFLCIHPFNDG
NGRMSRLLTLLLLYKTGFIVGKYISIEKIIEESKETYYEVLQDSLVGWHE
NENDYKPFVNYMLGVIVNAYKEFESRTELVTNPNLTKSDRIREIIKDHIG
TITKAELLEMNPDISDTTVQRTLAKLLKNNDIKKIGGGRYTKYTWNTEEQ

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570301
MNESELYKELGILTKDKSKWAENIQYVSSLLNHESAKIQAKALWLLGEMG
LEYPDSIQDAVPMVASFCDSENALLRERAVNALGRIGRGNYNLIEPYWSD
LFRFASDDEPKVRLSFIWASENVATNTPDIYENHMSVFESLLHDIDDKVR
MESPEIFRVLGKRRPEFVIPYIEQLQKMAETDSNRVVRIHSLGAIKVTTS
K

>2654570302
MWNMIWPLVLIVGSNCFYNICTKSMPEGTNTFGALTVTYLVGAVLSAVLF
VVSVKPAGVLNEISKINWTSFVLGLVIVGLEAGYVFLYRAGWKVSNGALT
ANICLAIALIVIGFLLYKESISIKQVAGIVVCGFGLFLING

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

then

awk 'BEGIN{RS=ORS="\n\n"}index($0,"|K"){print}' file.txt

output

>2654570299|K03427
MITGELKNKIDGLWDVFAAGGLVNPLEVIEQITYLMFIKDLDDVDKRKEK
ESAMLGLPYKSIFAGEVKIGDRTIEGTQLKWSVFHDFSAGRMYAIMQEWV
FPFIKNLHSDKNSTYSKYMDDAIFKFPTPLLLSKVVDSLDEIYEIMNSTL
VLDVRGDVYEYLLNKIASAGRNGQFRTPRHIIRMMVEMVEPKADDVICDP
GDLLKVCKTKKTELLFLALFLRMLKVGGRCACIVPDGVLFGSSKAHKDIR
KQVVEENRLEAVISMPSGVFKPYAGVSTAILIFTKTGHGGTDNVWFYDMT
ADGYSLDDKRTPVSENDIPDIIERFKNLDKEIDRERTDKSFMVPKQDIAD
NDYDLSINKYKEVVYEKIEYPPTSEIMADIREIEMEIGKEMDELEKLLNI

>2654570303|K01153
MKNKELLKRVGYVVLICLSFFVATWYFFENNKICTICWIAIGSKNVYDLV
HRIKNSKKED

Explanation: I set row seperator and output row seperator to double newline on in other words blank line, so every section is treated as single row. Then I use index function to check if section contain |K. This function does return 0 if no match, position of match if found. print is done only in latter case. Note that this function accept string ("|K") rather than pattern (/\|K/), so I do not have to care about characters with special meaning like |. If you want to know more about RS, ORS or other built-in AWK variables read 8 Powerful Awk Built-in Variables – FS, OFS, RS, ORS, NR, NF, FILENAME, FNR

(tested in gawk 4.2.1)

CodePudding user response:

Using awk or sed:

sed -e '/|K/, /^$/ p; d' database.txt
awk '/\|K/, /^$/' database.txt

Both of these do the exact same things -- they check for a |K on a line and print until they see the next blank line. In the sed syntax, the print is the explicit p (the d following clears the buffer to move to the next input line), while the awk example leverages the more implicit awk "default action" behavior.

There is a little bit of difference between the version of regular expressions language the two tools use in the matching syntax -- in that the `|` character can have a special meaning, and so it must be escaped in the awk example.

For more understanding of the syntax, both awk and sed are documented in their "man pages" -- refer to this documentation to figure out more about how the languages work.

  • Related