以下のようなファイルがあります:
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="***"
、"\*{3}"
、"\*\*"
(AWKは通常のアスタリスクのように処理するため機能しません)、"\\*\\*"
、または可能なあらゆる正規表現を配置しようとしました考えてみてください、しかしそれは機能していません(それは何も印刷していません)。
なぜなのかご存知ですか?
そうでない場合は、私の問題に対処する別の方法を知っていますか?
解析したいファイルの抜粋の下:
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}'`
2つの区切り文字の間で印刷するようにawkに指示します。具体的には:
awk '/\*{4,}/,/<np>/' file
これは区切り文字を含む行も出力するので、次のようにしてそれらを削除できます:
awk '/\*{4,}/,/<np>/' file | tail -n +2 | head -n -1
または、行が1番目の区切り文字と一致する場合は変数をtrueに設定し、2番目の区切り文字と一致する場合はfalseに設定し、trueの場合にのみ出力することができます。
awk '/\*{4,}/{a=1; next}/<np>/{a=0}(a==1){print}' file
上記のコマンドは、現在の行が4つ以上の*
に一致する場合、a
を1に設定し、next
行にもスキップします。これは、***
行が印刷されないことを意味します。
これは、元の誤解されたバージョンの質問への回答でした。少し異なる状況で役立つ可能性があるため、ここに残しておきます。
まず、FS
(フィールドセパレーター)ではなく、RS
(レコードセパレーター)が必要です。次に、リテラル*
を渡すには、2回エスケープする必要があります。 1回は*
をエスケープし、もう1回はバックスラッシュをエスケープします(それ以外の場合、awkは\r
または\t
と同じ方法で一致させようとします)。次に、2番目の「行」を印刷します。
$ awk -vRS='\\*\\*\\*' 'NR==2' file
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
出力の周りの空白行を回避するには、次を使用します。
$ awk -vRS='\n\\*\\*\\*\n' 'NR==2' file
thingsIwantToRead1
thingsIwantToRead2
thingsIwantToRead3
これは、表示されている最初の段落の後だけでなく、each段落の後に***
を想定していることに注意してください。
@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
段落が長すぎない場合。
Perlの使用:
< inputfile Perl -0777 -pe 's/.*[*]+\n(.*) <np>\n.*/$1/s' > outputfile
< inputfile
:inputfile
のコンテンツをPerl
のstdin
にリダイレクトします-0777
:Perlに、1行ずつではなくファイル全体を一度にスラップさせる-p
:Perlに行を印刷させる-e
:Perlに引数からプログラムの行を読み取らせる> outputfile
:Perl
の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$
Perlの使用:
< inputfile Perl -0777 -pe 's/.*[*]{3}\n(.*\n)\n.*/$1/s' > outputfile
< inputfile
:inputfile
のコンテンツをPerl
のstdin
にリダイレクトします-0777
:Perlに、1行ずつではなくファイル全体を一度にスラップさせる-p
:Perlに行を印刷させる-e
:Perlに引数からプログラムの行を読み取らせる> outputfile
:Perl
の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$