同じパターン間のawkまたはsed行(最初の一致を含む)

同じパターン間のawkまたはsed行(最初の一致を含む)

以下はテキストです。

* Tue This is the first line

– info 1

– info 2

– info 3

* Wed This is not to be included

このテキストの出力は次のようになります。

* Tue This is the first line

– info 1

– info 2

– info 3

注:awkとsedを試しましたが、出力を取得できませんでした。問題は、STARTとENDが同じ「*」(アスタリスク)で、最初の項目を出力に含める必要があることです。

答え1

私はこれを正しく理解することを願っています。このスクリプトは、2 行目からバッファーの終わりまで*すべてを削除し、例で目的の出力を生成します。

sed -n 'H;1h;$x;$s/\(\*[^*]*\)\n\*.*$/\1/p'

説明H保持バッファにすべての行()を追加します。最後の行では、ホールドバッファとパターンバッファ($x)を置き換えてファイル全体を1つのパターンにします。このモードでは、保持される部分が設定\(\)および維持され( \1)、改行内のすべての内容は*削除されます。

これは説明には適していますが、すべての可能な例に合わない場合は、スクリプトを変更できます。

答え2

perl -lne 'if ( m?^\*? ... m?^\*? ) { print if !// || !$a++ }'

sed -e '
   /^\*/!d
   :loop
       $q; N
   /\n\*/!bloop
   s/\(.*\)\n.*/\1/;q
'

sed -e '
   /^\*/!d
   :loop
      n
   //!bloop
   Q
'

答え3

サンプルテキストを変数に保存します。

$ SAMPLE=$(cat <<EOF
* Tue This is the first line

– info 1

– info 2

– info 3

* Wed This is not to be included
* Tue This is the first line

– info 1

– info 2

– info 3

* Wed This is not to be included
EOF
)

処理awk方法$SAMPLE

$ awk '{if($1~"\*"){if(p==1){p=0;next}else{p=1}}if(p==1){print $0}}' <<<"$SAMPLE"
* Tue This is the first line

– info 1

– info 2

– info 3

* Tue This is the first line

– info 1

– info 2

– info 3

編集する

コメントで提案したように、驚くほどエレガントなawkソリューションがあります。

$ awk '/^\*/{p=!p};p' <<<"$SAMPLE"
* Tue This is the first line

– info 1

– info 2

– info 3

* Tue This is the first line

– info 1

– info 2

– info 3

仕組み:

  • /^\*/{p=!p};p- の値が変わります1。正規表現を初めて発見すると0なります。二番目に見つかるとそうなります。1/^\*/p0

  • p- これはと同じですp{print}。は基本操作なので、print前提条件がその値に評価されると(この場合になると)awk常に印刷されます。truep1

関連情報