2016-10-27 1 views
1

を無視して、私は、以下に説明するようにSTARTとENDキーワードの間に線を削除するには、どのようなテキストファイルの範囲:は完全に形成された行を削除するだけで開始デリミタを有するもの

START 
text1 
text2 
text3 
START 
text4 
END 
text5 
text6 
START 
test7 
START 
test8 
END 

私の問題は、STARTキーワードであります常にENDで閉じられるとは限りません。上記の例のように、最初のSTARTはENDで終了せず、TEXT3の後にもう一度STARTを終了しました。それはまた、TEXT 4とTEXT7-8にTEXT1から行を削除しますので

sed '/START/,/END/d' test.txt 

は、だから私は、次のsedコマンドを使用することはできません。

しかし、TEXT4とTEXT8の行だけを削除します。だから、次の出力は次のようにする必要があります:

START 
text1 
text2 
text3 
text5 
text6 
START 
text7 
+0

@kaylumいいえ、それは異なっています。 – Bootsector

+1

@ mklement0タイトルを編集していただきありがとうございます。 :) – Bootsector

答えて

2

ファイルは行単位を反転させることにより容易になる:AWKで

$ tac test.txt | sed '/END/,/START/d' | tac 
START 
text1 
text2 
text3 
text5 
text6 
START 
test7 
1

この答えは使用高度なGNU固有の機能のために興味があるかもしれGNUawkソリューションです。
そうでない場合:


あなたはGNUawkを持っている場合は、次のことを試すことができます:

awk -v RS='(^|\n)START|END(\n|$)' ' 
    RT ~ "END" { 
    skipped=1 
    next 
    } 
    NF { 
    print (skipped ? "" : "START\n") gensub("^\n+|\n+$", "", "g") 
    skipped=0 
    } 
' test.txt 
登場する言葉 STARTまたは ENDによって(複数行)レコードに入力を壊す -v RS='(^|\n)START|END(\n|$)'
  • (単独で)行に表示されます。

    • これは、POSIXが入力レコード区切り文字RSのリテラルな単一文字値だけをサポートしているという点で、GNU拡張です。
  • RT ~ "END"(正規表現マッチングを使用して)レコード終了、RTにサブENDを探します。

    • RTは、現在の入力レコードの末尾にある実際のレコードターミネータを含むGNU固有の変数です。これは手元に記録がRTENDが含まれている場合、我々は完全に形成された範囲の中にいることを知って、私たちはこのレコードをスキップしている示すフラグを設定し、スキップを行うSTARTEND
    • に終わったかどうかを伝えることができますnextを実行します。
  • パターンNFNF > 0の略であり、手で記録が空である場合に対応するブロックにのみ実行されることを保証する(RS値に基づいて、非常に最初の入力レコードは空になります。但し、このこと隣接する線も排除される)。

    • print (skipped ? "" : "START\n") gensub("^\n+|\n+$", "", "g")現在のレコードを出力:

      • (skipped ? "" : "START\n")は、前のレコードが完全に形成された範囲なかった場合にのみSTARTと出力に先行します。そうであれば、基本的には入力から切り捨てられ、新しい範囲は開始されません。 (警告:入力がSTARTラインではない開始をしている場合、これは1を挿入します。)

      • gensub("^\n+|\n+$", "", "g")が手で入力レコードからすべての先頭と末尾の改行を置換し、その結果を返し、余分なを避けるために、出力の空行。

        • gensub()修正されたコピーのPOSIX準拠の兄弟、gsub()に追加機能を追加しますGNU固有の機能である、と、gsub()とは異なり、その場で入力文字列を変更しませんが、戻り代わりに
    • skipped=0前のレコードが完全に形成された範囲であったことを示すフラグをリセットします。

+0

ソリューションに感謝しますが、行を削除しませんでした。私がGNU awkを使用しているかどうかはどうすれば分かりますか?私はUbuntu 16.04を使用していてgawkをインストールしています。 – Bootsector

+0

Ubuntuの_default_ 'awk'は[Mawk](http://invisible-island.net/mawk/mawk.html)ですが、これはうまく動作しません。 Gawkがインストールされている場合は、 'awk'の代わりに' gawk'コマンドを実行してみてください。あなたのawkが何であるかを見るために 'awk -W v'を実行してください。 – mklement0

+0

awkからの出力-W -v: "GNU Awk 4.1.3、API:1.1(GNU MPFR 3.1.4、GNU MP 6.1.0)" – Bootsector

2

$ cat foo.awk 
/START/ { printf "%s", b; b="" }      # at START output buffer and empty it 
{ b=b $0 ORS }           # gather buffer 
/END/ { b="" }           # at empty buffer at END also 
END { printf "%s", b }         # Thanks @mklement0, this is needed 

を実行し、それ:

$ awk -f foo.awk foo 
START 
text1 
text2 
text3 
text5 
text6 
START 
test7 
+1

はい、ありがとうございます更新(と私の修正を修正:);あなたの 'awk'ソリューションは、POSIXに準拠しているという利点があります(私と違って)。 – mklement0

-1
awk '{sub(/text4|END/,"")}/START/{c++;if(c==2)sub("START","")}length;/test7/{exit}' file 

    START 
    text1 
    text2 
    text3 
    text5 
    text6 
    START 
    test7 
+1

特定のサンプル入力でのみ機能するハードコードされた値に基づくソリューションは役に立ちません。 – mklement0

関連する問題