パターンマッチング後に前の行を印刷するためにsedを使用しますか?

パターンマッチング後に前の行を印刷するためにsedを使用しますか?

一致するものが見つかるたびに前の行を印刷したいと思います。理解grep -Aして-B選択します。しかし、私のSolaris 5.10システムはこれらのオプションをサポートしていません。

だけ使用したいですsed

Foo.txt:

Name is : sara
age is : 10
Name is : john
age is : 20
Name is : Ron
age is : 10
Name is : peggy
age is : 30

Out.txt:

Name is : sara
Name is : Ron

私が一致させたいパターンはage is : 10

私の環境はSolaris 5.10。

答え1

$ sed -n '/age is : 10/{x;p;d;}; x' Foo.txt 
Name is : sara
Name is : Ron

上記はGNU sedでテストされました。 Solarisのsedがセミコロンで接続コマンドをサポートしていない場合は、次のようにします。

$ sed -n -e '/age is : 10/{x;p;d;}' -e x Foo.txt 
Name is : sara
Name is : Ron

どのように動作しますか?

sedには保留スペースとパターンスペースがあります。改行文字はパターン空間として読み込まれます。スクリプトのアイデアは、前の行を予約済みスペースに保存することです。

  • /age is : 10/{x;p;d;}

    現在行に が含まれている場合は、age is : 10次を実行します。

    x:前の行がパターンスペースにあるようにパターンを交換してスペースを予約します。

    p:前の行を印刷します。

    d:パターン空間を削除し、次のライン処理を開始します。

  • x

    これはを含まない行でのみ行われますage is : 10。この場合、現在の行を予約済みスペースに保存します。

逆にしなさい

年齢を次のように印刷したいとします。いいえ10:

$ sed -n -e '/age is : 10/{x;d}' -e '/age is :/{x;p;d;}' -e x Foo.txt 
Name is : john
Name is : peggy

上記のコマンドは、最初に/age is : 10/{x;d}10歳未満のユーザーを無視するようにコマンドを追加します。次のコマンドは、残りの/age is :/{x;p;d;}期間をすべて受け入れます。

答え2

POSIX的に:

$ sed -n '/age is : 10/{g
1!p
}
h
' file

現在の行が一致しない場合は、前の行を印刷しますage is : 10

$ sed -n '
$!N
/age is : 10/d
P
' file

答え3

以前のバッファは、h1行を格納するのに適していました。(または一連の行)後でいくつかのテストでそれが正しいことが証明されるまでです。つまり、連続しているが連続的ではないデータシーケンスを処理するのに適しています。しかし、シーケンシャル - 互いに貼り付けることができるからです。ただし、2 つのバッファ間で多くのコピーが必要です。前のコマンドを使用して一連の行を作成する場合(追加するだけで)悪くはありませんが、バッファをH変更するたびにxバッファ全体を別のバッファにコピーし、その逆も同様です。

すでに連続している一連の行を処理し、コンテキストに従ってそれらを切り取りたい場合のより良い方法は、ビューを使用することです。最初h- 既存バッファの様子とは異なり -後ろにcuonglmがこれをするすでに彼の答えの後半ですが、このロジックを2つの形式のうちの1つとして使用できます。

sed '$!N;/\nage.*: 10/P;D' <infile >outfile

これは、最後の行ではなく、行の現在のパターンスペースNに含まれる改行区切り文字の後に拡張入力行を追加することに注意してください。\nその後、インポートされた行がパターンと一致することを確認し、一致する場合はパターンスペースの最初の行にのみ印刷するため、前の行のみが印刷されます。最後に、パターン空間の最初の行を削除し、ループを再開します。したがって、ファイル全体で1行を探し続けます。!$P\nD\n最初不必要にバッファを交換する必要はありません。

コマンドを少し変更すると、ファイル全体にわたって2行のウィンドウをプッシュして、正確にどのように機能するかを確認できます。l前にookコマンドを追加しますD

sed '$!N;/\nage.*: 10/P;l;D'

Name is : sara
Name is : sara\nage is : 10$
age is : 10\nName is : john$
Name is : john\nage is : 20$
age is : 20\nName is : Ron$
Name is : Ron
Name is : Ron\nage is : 10$
age is : 10\nName is : peggy$
Name is : peggy\nage is : 30$
age is : 30$

これが出力です。で終わる行は、パターン空間のエスケープバージョンを標準出力としてレンダリングする$ookコマンドの結果です。lで終わらない行は印刷$されない行ですP。ご覧のとおり、前の行は、Pパターンスペースの2番目の行(Nちょうどドラッグされた追加の行とパターン\nスペースのewlineの後ろの行)がパターンと一致する場合にのみ印刷されます。

すでに提供されているソリューションに加えて、印刷のための他の方法を選択できます。名前前の行年齢いいねいいえ10で終わる:

sed -n '/^Name/N;/ 10$/!s/\nage.*//p'

...パターンスペースが文字列で始まる場合、\newlineと拡張入力行のみが追加されます。N名前p、パターンスペースが文字列で終わらない場合にのみ出力する行を印刷します。10 そしてewlineの後に文字列を正常に変更sedできる場合s///\n年齢そして、パターン空間が終わるまで続くすべて。編集コマンド(extなど\n)の結果を除いて、パターンスペースにewlineが存在できないため、N名前印刷された行は次のようになります。年齢いいねいいえ文字列で終わる10

上記の回答で使用されているすべての構文はPOSIX標準です。これはsed、その標準をサポートするすべての構文と同じように機能する必要があります。

関連情報