AWKを使用して***で区切られた段落を抽出します。

AWKを使用して***で区切られた段落を抽出します。

次のファイルがあります。

blablabla
blablabla
***
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3

blablabla
blablabla

で段落を抽出したいと思いますthingsIwantToRead。このような問題に対処する必要があるとき、私は次のものを使用しました。AWKこのように:

awk 'BEGIN{ FS="Separator above the paragraph"; RS="" } {print $2}' $file.txt | awk 'BEGIN{ FS="separator below the paragraph"; RS="" } {print $1}'

効果がありました。

この場合にはFS="***"、、 (AWKが一般アスタリスクで処理するため動作しません)または私が考えられる正規表現を入力してみましたが動作しません(何も印刷しません)"\*{3}""\*\*""\\*\\*"

理由をご存知ですか?

そうでなければ、私の問題を解決する他の方法を知っていますか?

以下は、解析したいファイルから抜粋したものです。

13.2000000000     , 3*0.00000000000       ,  11.6500000000     , 3*0.00000000000       ,  17.8800000000

Blablabla

  SATELLITE EPHEMERIS
     ===================
Output frame: Mean of J2000

       Epoch                  A            E            I           RA           AofP          TA      Flight Ang
*****************************************************************************************************************
2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311
 <np>
 ----------------
 Predicted Orbit:
 ----------------

 Blablabla

私は以下を抽出したい:

2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311

* 行の後の数字を取得しようとしたコマンドは次のとおりです。

`awk 'BEGIN{ FS="\\*{2,}"; RS="" } {print $2}' file | awk 'BEGIN{ FS="<np>"; RS="" } {print $1}'`

答え1

2つの区切り文字の間を印刷するようにawkに指示します。具体的には:

awk '/\*{4,}/,/<np>/' file

区切り文字を含む行も印刷されるため、次のように区切り文字を削除できます。

awk '/\*{4,}/,/<np>/' file | tail -n +2 | head -n -1

または、行が最初の区切り文字と一致する場合は変数をtrueに設定し、2番目の区切り文字と一致する場合はfalseに設定し、trueの場合にのみ印刷できます。

awk '/\*{4,}/{a=1; next}/<np>/{a=0}(a==1){print}' file

a現在の行が4つ以上に一致する場合、上記のコマンドはこれを1に設定し、その行に*ジャンプnextします。これは、対応する***行が印刷されないことを意味します。


これは質問の元の誤解されたバージョンへの答えです。少し違う状況で役に立つかもしれませんので、ここに残しておきます。

FSまず、(フィールド区切り記号)を必要とせずRS(レコード区切り記号)が必要です。その後、リテラルを渡すには*2回エスケープする必要があります。一度はバックスラッシュをエスケープし*、一度はバックスラッシュをエスケープします(そうでなければ、awkは\rorと同じ方法で一致しようとします\t)。次に、2番目の「行」を印刷します。

$ awk -vRS='\\*\\*\\*' 'NR==2' file

thingsIwantToRead1   
thingsIwantToRead2   
thingsIwantToRead3  

出力の周りに空白行を避けるには、次のようにします。

$ awk -vRS='\n\\*\\*\\*\n' 'NR==2' file
thingsIwantToRead1   
thingsIwantToRead2   
thingsIwantToRead3  

これは***後で想定されます。提示する最初の段落の直後ではなく、段落。

答え2

@terdonの答えに加えて、awk(とsed)を使用すると、スコープモードを使用できます。

awk '/sep1/,/sep2/{print}' file

または

sed -n '/sep1/,/sep2/p' file

sep1以下を含むすべてを印刷しますsep2

~$ awk '/sep1/,/sep2/{print}' file
sep1
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
sep2

あなたの場合:

~$ awk '/\*\*\*/,/^$/{print}' file
***
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
 

その後、最初の行と最後の行を削除できます。

たとえば、

~$ sed -n '/\*\*\*/,/^$/p' file | sed '1d;$d'
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3

または

~$ awk '/\*\*\*/,/^$/{print}' file | awk 'NR>1&&!/^$/ {print}'
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3

段落が長すぎない場合。

答え3

sedこの問題を解決するには2つの方法があります。あなたは選ぶことができます含むまたはただ。あなたの場合含まれる選択とは、一致で始まるすべての行を印刷することを意味し、'^*\*\*'そのうちの最大1つを含みます。^ *<np> (それは何でも)または^$空白行。

一つ含まれる他の回答で説明されている範囲式のいずれかを使用して選択項目を指定できます。ここで印刷開始モードは次に渡されます。ここまで全部過ぎた柄。

一つ排他的別の道に行くことを選択してください。それ次の前に印刷を停止してください。モードは次に渡されます。ここから印刷を開始柄。あなたのサンプルデータについて - そして許可次の前に印刷を停止してください。空行に一致するパターンまたはその<np>仕事:

sed -e 'x;/^\( *<np>.*\)*$/,/^*\** *$/c\' -e '' <infile >outfile
  • x
    • ホールド空間とパターン空間を交換します。その機関は後ろを見てsed- 入力後は常に1行 - そして最初の行は常に空です。
  • /^\( *<np>.*\)*$/
    • これは以下を選択します。次の前に印刷を停止してください。最初から最後まで0回以上一致するグループの行と一致します。ゼロ個以上の項目と一致できる2つの種類の行があります。つまり、空白行または空白行が複数ある行です。<スペース>行の先頭に文字列が続きます<np>
  • /^*\** *$/
    • これは以下を選択します。ここから印刷を開始1つ以上の*アスタリスク文字で始まり、行の終わりまで続き、*アスタリスクが0個以上発生し、スペースの数に制限なく終わることができる行。
  • c\' -e ''
    • これにより、cブロックされた選択肢全体が空白行になり、不要な行がすべて文字列に圧縮されます。EOF

^*\** *$したがって、最初の後続の段落の前後に表示される行数は^\( *<np>.*\)*$常に1つの空白に圧縮され、その段落の最初の項目のみが圧縮されます。後ろに一致は^*\** *$標準出力として印刷されます。印刷されます...

2012/10/01 00:00:00.000 6998.239 0.001233 97.95558 77.41733 89.98551 290.75808 359.93398
2012/10/01 00:05:00.000 6993.163 0.001168 97.95869 77.41920 124.72698 274.57362 359.93327
2012/10/01 00:10:00.000 6987.347 0.001004 97.96219 77.42327 170.94020 246.92395 359.94706
2012/10/01 00:15:00.000 6983.173 0.000893 97.96468 77.42930 224.76158 211.67042 359.97311

入力に表示される段落パターンを必要なだけ処理しようとしているとします。欲しいなら最初しかし、GNUgrepinfile正規、検索可能文書:

{   grep -xm1 '*\** *'        >&2
    sed -n '/^\( *<np>.*\)*$/q;p'
}   <infile 2>/dev/null >outfile

...やはり動作します。

実際に私の考えではサム方法。 3番目は次のとおりです。

sed 'H;$!d;x;s/\(\n\*\** *\n\(\([0-9./: ]*\n\)*\)\)*./\2/g'

...ファイル全体を読み、一致する行仕様に属していないすべての文字をグローバルに置き換えます。以前と同様にうまく印刷されますが、書き込みが難しく、オプションオプションのバランスを取る場合にのみ安全なパフォーマンスを発揮します。どの特徴。

答え4

質問の編集に従って更新されたバージョン:

パールの使用:

< inputfile perl -0777 -pe 's/.*[*]+\n(.*) <np>\n.*/$1/s' > outputfile
  • < inputfile:コンテンツを「s」inputfileにリダイレクトします。perlstdin
  • -0777:Perlにファイルを1行ずつ読み込むのではなく、一度にファイル全体を読み取るようにします。
  • -p:Perlにこの行を印刷するように強制します。
  • -e: Perl に引数からプログラムラインを読み込むように強制します。
  • > outputfileperl:コンテンツをstdout次にリダイレクトします。outputfile

正規表現の分解:

  • s: 置換を実行するためのアサーション
  • /: 検索モード開始
  • .*[*]+\n*: 改行文字の直後に 1 つ以上の文字で終わる文字列の最後まで、すべての文字と一致します。
  • (.*) <np><np>\n:次の文字列の文字まで、必要な数のすべての文字を一致させてグループ化します。
  • .*:任意の数のすべての文字と一致します。
  • /:検索モードを停止/交換モードを開始
  • $1:キャプチャされたグループに置き換えられました
  • /:交換モード停止/修飾子開始
  • s: 入力文字列が単一行として処理され、.改行文字も一致することを指定します。

出力例:

~/tmp$ cat inputfile
13.2000000000     , 3*0.00000000000       ,  11.6500000000     , 3*0.00000000000       ,  17.8800000000

Blablabla

  SATELLITE EPHEMERIS
     ===================
Output frame: Mean of J2000

       Epoch                  A            E            I           RA           AofP          TA      Flight Ang
*****************************************************************************************************************
2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311
 <np>
 ----------------
 Predicted Orbit:
 ----------------

 Blablabla
~/tmp$ < inputfile perl -0777 -pe 's/.*[*]+\n(.*) <np>\n.*/$1/s'
2012/10/01 00:00:00.000     6998.239     0.001233     97.95558     77.41733     89.98551    290.75808    359.93398
2012/10/01 00:05:00.000     6993.163     0.001168     97.95869     77.41920    124.72698    274.57362    359.93327
2012/10/01 00:10:00.000     6987.347     0.001004     97.96219     77.42327    170.94020    246.92395    359.94706
2012/10/01 00:15:00.000     6983.173     0.000893     97.96468     77.42930    224.76158    211.67042    359.97311
~/tmp$ 

オリジナル:

パールの使用:

< inputfile perl -0777 -pe 's/.*[*]{3}\n(.*\n)\n.*/$1/s' > outputfile
  • < inputfile:コンテンツを「s」inputfileにリダイレクトします。perlstdin
  • -0777:Perlにファイルを1行ずつ読み込むのではなく、一度にファイル全体を読み取るようにします。
  • -p:Perlにこの行を印刷するように強制します。
  • -e: Perl に引数からプログラムラインを読み込むように強制します。
  • > outputfileperl:コンテンツをstdout次にリダイレクトします。outputfile

正規表現の分解:

  • s: 置換を実行するためのアサーション
  • /: 検索モード開始
  • .*[*]{3}\n***\n: 文字列が終了する前のすべての文字と一致します。
  • (.*\n)\n:改行文字まで含め、その後に改行文字が続く文字を必要な数だけ一致させてグループ化します。
  • .*:任意の数のすべての文字と一致します。
  • /:検索モードを停止/交換モードを開始
  • $1:キャプチャされたグループに置き換えられました
  • /:交換モード停止/修飾子開始
  • s: 入力文字列が単一行として処理され、.改行文字も一致することを指定します。

出力例:

~/tmp$ cat inputfile
blablabla
blablabla
***
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3

blablabla
blablabla
~/tmp$ < inputfile perl -0777 -pe 's/.*[*]{3}\n(.*\n)\n.*/$1/s'
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
~/tmp$ 

関連情報