Поиск определенных слов и удаление всех строк после них

С помощью sed вы можете получить первые 30 символов:

sed 's|\(.\{30\}\).*|\1|'

и использовать их вместо cut в цикле for.

Суть этой подстановки sed в том, что то, что совпадает между \( \), вы заменяете на \1. {30} (экранированный \) считает 30 отдельных символов (. ).

3
20.04.2017, 11:34
4 ответа

awk обычно легче читать и понимать:

Вот простая программа, которая записывает по умолчанию и переключает «wewrite» на «0» (= выключено, мы не будем писать), когда видит строку, где первое слово — «ген», и верните его, когда он увидит строку, где первое слово — «CDS» или «мРНК»:

awk '
  BEGIN                               { weprint=1 }

  ( $1 == "gene" )                    { weprint=0 }
  ( $1 == "CDS" ) || ( $1 == "mRNA" ) { weprint=1 }
  ( weprint == 1)                     { print $0 ;}

  '  file_to_read

НАЧАЛО выполняется до того, как будут прочитаны какие-либо строки.

Другие действия ( test ) { если тест прошел успешно } анализируются для каждой строки ввода (... если действие не содержит next, которое затем будет игнорировать остальную часть те и вместо этого пошли бы на следующую строку ввода)

Это напечатает только разделы «CDS» и «мРНК», а не «ген»

Это может быть «игра в гольф» (например, действие по умолчанию для Успешный "тест" должен напечатать $0, поэтому вы могли бы иметь только ( weprint == 1) в качестве последней строки, но это было бы менее понятно, imo...)

4
27.01.2020, 21:11

Я не могу удержаться от ответа perl , когда у нас есть ответы sed и awk !

# make perl complain when it should
use strict;
use warnings;

# declare variable
my $section;

# run through every line
while (<>) {
  # set the current section to 'gene', 'CDS' or 'mRNA' when it matches
  $section = $1 if /^\h*(gene|CDS|mRNA)/;

  # print if the current section is not 'gene'
  print if $section ne 'gene';
}
1
27.01.2020, 21:11
sed -e '
   /^ *gene /!b   # print non-gene block begin lines
   :a  
   $d; N          # do-while loop accumulates lines for gene block
   s/\n *\///;ta
   D              # clip the gene block
' yourfile

Вы должны понимать, что модель sed предназначена для чтения файла построчно основе, а команда sed в секции -e применяется последовательно на строка по мере ее преобразования, если нет инструкций ветвления вовлеченный.И основной синтаксис sed — это адресная команда, где команда может любая допустимая команда sed, а адрес может быть любым из следующих: linenum, $ (= последняя строка), регулярное выражение, диапазон адресов, и, наконец, ничего не означает, что это получает применяется ко ВСЕМ линиям. Обратите внимание, что строки хранятся в регистре, называемом пространством шаблонов.

Итак, отбросив эти основные вещи, мы переходим к фактическому коду sed -e под рукой: b => перейдите в конец кода sed и напечатайте пространство шаблонов. Это означает, что мы продолжаем печатать любую строку, которая НЕ (! после шаблона адреса) содержит строку gene в качестве первого поля.

Когда мы, наконец, наткнулись на ген в первой строке поля, мы создали цикл do-while (:a устанавливает метку для перехода), чтобы продолжать накапливать строки в регистр пространства шаблона (N добавляет следующую строку; команда s удаляет \n *\/, что является разрывом строки, за которым следуют пробелы и a /) до тех пор, пока не будет выполнено одно из двух условий, а именно, либо мы нажмем eof => мы удалим его ($d => удалим пространство шаблонов, если мы находятся в последней строке), так как это генный блок, который появился ближе к eof и должен уйти.

ИЛИ мы попадаем в начало следующего блока: если s может найти и удалить указанный шаблон, t перейдет к :a, иначе ( новый блок, значит шаблон не найден), продолжаем.Теперь пространство шаблонов содержит весь генный блок и первую строку следующего блока. Оперативно удаляем блок генов и с началом следующего блока переходим в начало кода sed (что и делает команда D).

3
27.01.2020, 21:11

Вот программа sed -для удаления блока строк из файла, где каждый блок начинается со строки определенного шаблона и заканчивается там, где начинается следующий блок. (Я мог бы назвать такого рода блоки разделами , и задачей было бы удалить раздел с помощью sed.)

Начнем с очевидной попытки решить эту (аналогичную предложению из комментария @Stéphane -Chazelas ), которое, однако, не сработает:

sed '/^     gene/,/^     [^ ]/ d'

Наш раздел заканчивается, и следующий раздел начинается, когда в начале строки есть 5 пробелов, за которыми следует не -пробел. Наш раздел начинается с 5 пробелов и gene.

Проблема с этой простой программой sed -заключается в том, что диапазон адресов совпадает также с начальной строкой следующего раздела и также удаляет ее.

Но это работает:

end='^     [^ ]'
begin='^     gene'
sed --regexp-extended -e "/$begin/,/$end/ {
        /$end/! d # skip the end, otherwise delete
        /$begin/ d # do not skip (even if it happens to match end)
    }" \
    -i -- "$@"

Попытка на вашем примере дает желаемый результат:

$ cp example-stackexchange-360117.txt{.orig,} -vf
'example-stackexchange-360117.txt.orig' -> 'example-stackexchange-360117.txt'
$./delete-section2-gene example-stackexchange-360117.txt
$ diff example-stackexchange-360117.txt{.orig,}
1,3d0
<      gene            3025..3855
<                      /gene="Sp34_10000100"
<                      /ID="Sp34_10000100"
11,13d7
<      gene            12640..13470
<                      /gene="Sp34_10000200"
<                      /ID="Sp34_10000200"
21,23d14
<      gene            15959..20678
<                      /gene="Sp34_10000300"
<                      /ID="Sp34_10000300"
31,33d21
<      gene            22255..23085
<                      /gene="Sp34_10000400"
<                      /ID="Sp34_10000400"
$ 

Обратите внимание, что он даже волшебным образом удалил последний раздел в конце файла, хотя нет следующей строки, которая соответствовала бы $end! (Причина мне не ясна из руководства GNU sed.)

У меня была аналогичная проблема, для которой я придумал это решение :удалить определение всей функции из источника Python, а именно из Lib/test/audit -test.py из исходников Python 3.8.1.

Я использовал один и тот же сценарий с разными шаблонами:

end='^[^[:blank:]]'
begin='^def.*winreg'
sed --regexp-extended -e "/$begin/,/$end/ {
        /$end/! d # skip the end, otherwise delete
        /$begin/ d # do not skip (even if it happens to match end)
    }" \
    -i -- "$@"

и это сработало хорошо, удалив ровно одно определение функции, которое заканчивается там, где отступ снова является верхним уровнем (, т. е. следующий раздел начинается с нулевого отступа):

$ git checkout 3.8
$../delete-section2 Lib/test/audit-tests.py 
$ git --no-pager diff
diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index 33f320992b..ed08612c04 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -304,29 +304,6 @@ def test_unraisablehook():
     write_unraisable_exc(RuntimeError("nonfatal-error"), "for audit hook test", None)


-def test_winreg():
-    from winreg import OpenKey, EnumKey, CloseKey, HKEY_LOCAL_MACHINE
-
-    def hook(event, args):
-        if not event.startswith("winreg."):
-            return
-        print(event, *args)
-
-    sys.addaudithook(hook)
-
-    k = OpenKey(HKEY_LOCAL_MACHINE, "Software")
-    EnumKey(k, 0)
-    try:
-        EnumKey(k, 10000)
-    except OSError:
-        pass
-    else:
-        raise RuntimeError("Expected EnumKey(HKLM, 10000) to fail")
-
-    kv = k.Detach()
-    CloseKey(kv)
-
-
 if __name__ == "__main__":
     from test.libregrtest.setup import suppress_msvcrt_asserts

$ 

Вариант этой программы sed -с командой b("ветка"):


end='^[^[:blank:]]'
begin='^def.*winreg'
sed --regexp-extended -e "/$begin/,/$end/ {
        /$begin/ d # delete, do not skip
        /$end/ b # skip
        d # default action
    }" \
    -i -- "$@"
0
07.02.2020, 00:53

Теги

Похожие вопросы