次のファイルがあります。
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は\r
orと同じ方法で一致しようとします\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>
。
- これは以下を選択します。次の前に印刷を停止してください。最初から最後まで0回以上一致するグループの行と一致します。ゼロ個以上の項目と一致できる2つの種類の行があります。つまり、空白行または空白行が複数ある行です。<スペース>行の先頭に文字列が続きます
/^*\** *$/
- これは以下を選択します。ここから印刷を開始1つ以上の
*
アスタリスク文字で始まり、行の終わりまで続き、*
アスタリスクが0個以上発生し、スペースの数に制限なく終わることができる行。
- これは以下を選択します。ここから印刷を開始1つ以上の
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
入力に表示される段落パターンを必要なだけ処理しようとしているとします。欲しいなら最初しかし、GNUgrep
とinfile
正規、検索可能文書:
{ 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
にリダイレクトします。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$
オリジナル:
パールの使用:
< inputfile perl -0777 -pe 's/.*[*]{3}\n(.*\n)\n.*/$1/s' > outputfile
< inputfile
:コンテンツを「s」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$