특정 단어부터 시작하여 다음 유사한 블록(다음 유사한 "섹션 헤더")까지 줄 블록을 제거합니다.

특정 단어부터 시작하여 다음 유사한 블록(다음 유사한 "섹션 헤더")까지 줄 블록을 제거합니다.

다음 정보가 포함된 파일이 있습니다.

     gene            3025..3855
                     /gene="Sp34_10000100"
                     /ID="Sp34_10000100"
     CDS             join(3025..3106,3722..3855)
                     /gene="Sp34_10000100"
                     /codon_start=1
                     /ID="Sp34_10000100.t1.cds1,Sp34_10000100.t1.cds2"
     mRNA            3025..3855
                     /ID="Sp34_10000100.t1"
                     /gene="Sp34_10000100"
     gene            12640..13470
                     /gene="Sp34_10000200"
                     /ID="Sp34_10000200"
     CDS             join(12640..12721,13337..13470)
                     /gene="Sp34_10000200"
                     /codon_start=1
                     /ID="Sp34_10000200.t1.cds1,Sp34_10000200.t1.cds2"
     mRNA            12640..13470
                     /ID="Sp34_10000200.t1"
                     /gene="Sp34_10000200"
     gene            15959..20678
                     /gene="Sp34_10000300"
                     /ID="Sp34_10000300"
     CDS             join(15959..16080,16268..16367,18913..19116,20469..20524,20582..20678)
                     /gene="Sp34_10000300"
                     /codon_start=1
                     /ID="Sp34_10000300.t1.cds1,Sp34_10000300.t1.cds2,Sp34_10000300.t1.cds3,Sp34_10000300.t1.cds4,Sp34_10000300.t1.cds5"
     mRNA            15959..20678
                     /ID="Sp34_10000300.t1"
                     /gene="Sp34_10000300"
     gene            22255..23085
                     /gene="Sp34_10000400"
                     /ID="Sp34_10000400"

모두 삭제하고 싶어요유전자부분적으로는 그렇지만CDS그리고메신저 RNA정보가 거기에 있어야합니다. 출력은 다음과 같아야 합니다.

     CDS             join(3025..3106,3722..3855)
                     /gene="Sp34_10000100"
                     /codon_start=1
                     /ID="Sp34_10000100.t1.cds1,Sp34_10000100.t1.cds2"
     mRNA            3025..3855
                     /ID="Sp34_10000100.t1"
                     /gene="Sp34_10000100"
     CDS             join(12640..12721,13337..13470)
                     /gene="Sp34_10000200"
                     /codon_start=1
                     /ID="Sp34_10000200.t1.cds1,Sp34_10000200.t1.cds2"
     mRNA            12640..13470
                     /ID="Sp34_10000200.t1"
                     /gene="Sp34_10000200"
     CDS             join(15959..16080,16268..16367,18913..19116,20469..20524,20582..20678)
                     /gene="Sp34_10000300"
                     /codon_start=1
                     /ID="Sp34_10000300.t1.cds1,Sp34_10000300.t1.cds2,Sp34_10000300.t1.cds3,Sp34_10000300.t1.cds4,Sp34_10000300.t1.cds5"
     mRNA            15959..20678
                     /ID="Sp34_10000300.t1"
                     /gene="Sp34_10000300"

이 작업을 수행하는 방법에 대한 제안을 알려주십시오.

답변1

awk는 일반적으로 읽고 이해하기가 더 쉽습니다.

이것은 기본적으로 작성하는 간단한 프로그램입니다. 첫 번째 단어가 "gene"인 줄을 보면 "wewrite"를 "0"(= 꺼짐, 쓰지 않음)으로 전환하고 다음과 같은 경우 다시 켜는 것입니다. 그가 본 첫 번째 단어는 "유전자"입니다. 첫 번째 단어가 "CDS" 또는 "mRNA"인 줄을 참조하세요.

awk '
  BEGIN                               { weprint=1 }

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

  '  file_to_read

BEGIN은 행을 읽기 전에 완료됩니다.

다른 하나는 ( test ) { action if test successful }각 입력 줄을 구문 분석합니다(...작업에 가 포함되어 있지 않으면 next나머지는 무시하고 대신 다음 입력 줄을 가져옵니다).

이렇게 하면 "유전자" 부분이 아닌 "CDS" 및 "mRNA" 부분만 인쇄됩니다.

이는 "골프 공"일 수 있습니다. 예를 들어 성공적인 "테스트"를 위한 기본 작업은 $0을 인쇄하는 것이므로 ( weprint == 1)마지막 줄과 같은 작업을 수행할 수 있지만 제 생각에는 이해하기가 덜 명확합니다...)

답변2

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해당 줄에 순차적으로 적용된다는 점을 인식해야 합니다 . branching기본 구문 sedaddress commandcommand가 유효한 sed명령일 수 있고 address다음 중 하나일 수 있다는 것입니다: linenum, $(= 마지막 줄)​​, regex, , range of addresses, 마지막은 모든 줄에 적용된다는 의미는 없습니다. 행은 이름이 지정된 레지스터에 저장됩니다 pattern space.

따라서 이러한 기본 사항을 마치고 sed -e실제 코드로 넘어갑니다. b=> sed 코드 끝으로 분기하여 패턴 공간을 인쇄합니다. 즉 , 첫 번째 필드로 !문자열이 없는(주소 패턴 뒤) 모든 행을 계속 인쇄한다는 의미입니다 .gene

마지막으로 첫 번째 필드 행에 도달하면 genedo-while 루프( :a점프할 마커 설정)를 설정하여 패턴 공간 레지스터에 행을 계속 축적합니다( N다음 행 추가, 줄 바꿈인 sdelete 명령 \n *\/, 이어서 공백 및 a /) 두 조건 중 하나가 충족되지 않을 때까지, 즉 eof를 누르거나 => 삭제합니다( $d=> 마지막 줄에 있으면 패턴 공간을 삭제합니다). 이는 eof 및 Blocks 근처에서 발생하기 때문입니다. 삭제해야 할 유전자

또는 다음 블록의 시작 부분에 도달합니다. s해당 패턴을 찾아서 제거할 수 있으면 해당 패턴 t으로 점프하고 :a, 그렇지 않으면(새 블록이므로 패턴을 찾을 수 없음) 계속합니다. 이제 패턴 공간은 전체 유전자 블록과 다음 블록의 첫 번째 라인을 보유합니다. 우리는 유전자 블록을 즉시 삭제하고 다음 블록의 시작 부분에 있는 sed 코드의 맨 위로 이동합니다(명령이 수행하는 작업입니다 D).

답변3

나는주는 것을 거부 할 수 없다진주우리가 가끔 대답할 때sed그리고답변!

# 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';
}

답변4

이것은 파일에서 라인 블록을 제거하는 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 소스에서 전체 함수 정의를 제거합니다.라이브러리/테스트/audit-tests.pyPython 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 -- "$@"

들여쓰기가 다시 최상위 레벨인 곳에서 끝나는 함수 정의를 훌륭하게 제거합니다(즉, 다음 섹션은 들여쓰기 0에서 시작합니다).

$ 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

$ 

b명령("branch")을 사용하는 이 sed 프로그램의 변형 :


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

관련 정보