特定の単語から始まり、次の同様のブロック(次のような「セクションヘッダー」)まで行ブロックを削除します。

特定の単語から始まり、次の同様のブロック(次のような「セクションヘッダー」)まで行ブロックを削除します。

次の情報を含むファイルがあります。

     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は行を読み取る前に完了します。

もう 1 つは( 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モデルは、ファイルを1行ずつ読み込み、ディレクティブが含まれていない限り、変換時にそのセクションのコマンドがその行に順次sed適用-eされることを認識する必要があります。branching基本的な構文sedaddress command、コマンドが有効なsedコマンドであり、次のいずれかである可能 性があることですaddress。行は名前付きレジスタに保存されます。linenum$regexrange of addressespattern space

したがって、これらの基本を終えてsed -e実際のコードに進みます。 b=> sedコードの末尾に分岐してパターンスペースを印刷します。つまり、最初のフィールドに!文字列を持たない(アドレスパターンの後に)すべての行を印刷し続けることを意味します。gene

最後に、最初のフィールドの行に達すると、genedo-whileループ(:aジャンプするマーカー設定)を設定して、パターン空間レジスタに行を蓄積し続けます(次のN行を追加、改行sdelete コマンド\n *\/、続いて空白、a /) 1つが満たされなくなるまで、つまり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 -- "$@"

関連情報