Добавление # перед первыми 8 строками, соответствующими STRING

Вопрос немного сбивает с толку, поэтому я просто покажу пример.

Допустим, у меня есть следующий случай:

$ grep -P "locus_tag\tM715_1000193188" Genome.tbl -B1 -A8
193188  193066  gene
            locus_tag   M715_1000193188
193188  193066  mRNA
            product hypothetical protein
            protein_id  gnl|CorradiLab|M715_1000193188
            transcript_id   gnl|CorradiLab|M715_mrna1000193188
193188  193066  CDS
        product hypothetical protein
        protein_id  gnl|CorradiLab|M715_1000193188
        transcript_id   gnl|CorradiLab|M715_mrna1000193188

Я хочу добавить «#» к 8 строкам, следующим за «locus_tag M715_1000193188», чтобы мой измененный файл выглядел так:

193188  193066  gene
            locus_tag   M715_1000193188
#193188 193066  mRNA
#           product hypothetical protein
#           protein_id  gnl|CorradiLab|M715_1000193188
#           transcript_id   gnl|CorradiLab|M715_mrna1000193188
#193188 193066  CDS
#       product hypothetical protein
#       protein_id  gnl|CorradiLab|M715_1000193188
#       transcript_id   gnl|CorradiLab|M715_mrna1000193188

По сути, у меня есть файл с примерно 3000 различных тегов локуса, и для 300 из них мне нужно закомментировать функции мРНК и CDS, поэтому 8 строк после строки locus_tag.

Любой возможный способ сделать это с помощью sed? В файле есть и другие типы информации, которые нужно оставить нетронутыми.

Спасибо, Адриан


person AdrianP.    schedule 28.04.2015    source источник


Ответы (4)


Если вы можете использовать awk, это должно делать:

awk 'f&&f-- {$0="#"$0} /locus_tag/ {f=8} 1' file
193188  193066  gene
            locus_tag   M715_1000193188
#193188  193066  mRNA
#            product hypothetical protein
#            protein_id  gnl|CorradiLab|M715_1000193188
#            transcript_id   gnl|CorradiLab|M715_mrna1000193188
#193188  193066  CDS
#        product hypothetical protein
#        protein_id  gnl|CorradiLab|M715_1000193188
#        transcript_id   gnl|CorradiLab|M715_mrna1000193188
person Jotne    schedule 28.04.2015
comment
Красиво, работает! Как я могу внести изменения в файл напрямую? Мне нужно сделать это 300 раз, так можно ли вносить изменения в файл напрямую каждый раз, когда я редактирую? Допустим, у меня есть цикл for, в котором $i — это имя локуса, awk будет выглядеть так: awk 'f&&f-- {$0=#$0} /locus_tag\t$i/ {f=8} 1' файл - person AdrianP.; 28.04.2015
comment
Чтобы awk обновить исходный файл, выполните: awk 'commands' file >tmp && mv tmp file. Если у вас gawk ›= `4.1`, вы можете использовать gawk -i - person Jotne; 28.04.2015
comment
Или передать awk все значения локуса и внести все изменения за один проход во входном файле. - person Etan Reisner; 28.04.2015
comment
Я столкнулся с небольшой проблемой. Некоторые номера локуса, например M715_80001, являются проблематичными из-за частичного совпадения с другими номерами локуса, такими как M715_8000123 M715_80001654. Как я могу настроить это для точного совпадения? Я попытался добавить символ \n, но это не работает awk 'f&&f-- {$0=#$0} /locus_tag\tM715_80001\n/ {f=8} 1' - person AdrianP.; 30.04.2015
comment
Вы можете сделать: awk 'f&&f-- {$0="#"$0} $1=="locus_tag" && $2=="M715_80001" {f=8} 1' file - person Jotne; 30.04.2015

sed поддерживает диапазон адресов, которые могут делать здесь то, что вы хотите.

sed -e '/locus_tag\tM715_1000193188/,+8s/^/#/' file

Как отмечено в комментариях, этот формат адресов диапазона специфичен для GNU sed.

person Etan Reisner    schedule 28.04.2015
comment
Мне это нравится. Кроме того: sed понимает \t напрямую. Форма диапазонов /pattern/,+8 специфична для GNU; было бы разумно принять это к сведению. - person Wintermute; 28.04.2015
comment
Это решение комментирует 8 строк, следующих за строкой, а также строку, в которой находится строка. Можно ли не комментировать строку, в которой находится строка? Спасибо - person AdrianP.; 28.04.2015
comment
Хм... Хороший вопрос. Я не уверен, что sed может сделать это легко. Однако vim поддерживает такой диапазон. Я думаю, вам понадобится этикетка и тест на замену или что-то в этом роде для sed. - person Etan Reisner; 28.04.2015
comment
Есть ли способ сделать это, но для 2 строк перед матчем? Я пробовал -2 с вместо +8, но это не сработало. - person AdrianP.; 30.04.2015
comment
sed определенно не может так двигаться назад. Я не знаю, что sed тоже занимается математикой с диапазонами. vim может делать обе эти вещи, но не подходит для больших файлов. Вы можете сделать это с помощью awk, сохраняя скользящее окно строк вручную, но я не знаю ничего, что могло бы сделать это в потоковом режиме (возможно, perl, но я не знаю). - person Etan Reisner; 30.04.2015

$ cat tst.awk
BEGIN { split(tags,tmp); for (i in tmp) tagsA[tmp[i]] }
c&&c-- { $0 = "#" $0 }
($(NF-1) == "locus_tag") && ($NF in tagsA) { c=8 }
{ print }

$ awk -v tags="M715_1000193188 M715_1000193189 M715_1000193190" -f tst.awk file
193188  193066  gene
            locus_tag   M715_1000193188
#193188  193066  mRNA
#            product hypothetical protein
#            protein_id  gnl|CorradiLab|M715_1000193188
#            transcript_id   gnl|CorradiLab|M715_mrna1000193188
#193188  193066  CDS
#        product hypothetical protein
#        protein_id  gnl|CorradiLab|M715_1000193188
#        transcript_id   gnl|CorradiLab|M715_mrna1000193188

Просто перечислите все 300 значений тегов локуса, которые вам нужны, как показано выше для 3 примеров.

person Ed Morton    schedule 28.04.2015

Это может сработать для вас (GNU sed):

sed 's/.*/\\#locus_tag\\s*&#,+9{\\#locus_tag\\s*&#n;s|^|#|}/' tag_file |
sed -i -f - file

Это создает сценарий sed из файла тега и добавляет # к восьми строкам, следующим за совпадением в теге.

person potong    schedule 28.04.2015