С помощью sed
вы можете получить первые 30 символов:
sed 's|\(.\{30\}\).*|\1|'
и использовать их вместо cut
в цикле for
.
Суть этой подстановки sed
в том, что то, что совпадает между \( \)
, вы заменяете на \1
. {30}
(экранированный \
) считает 30 отдельных символов (.
).
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...)
Я не могу удержаться от ответа 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';
}
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
).
Вот программа 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 -- "$@"