web-dev-qa-db-ja.com

sedまたはawkを使用して、一致するパターンに続く行を印刷する

質問:一致するパターンを含む行の直後に単一行を印刷したい。

私のバージョンのsedは、次の構文を取りません(+1pを爆破します)。

sed -n '/ABC/,+1p' infile

私はawkが複数行処理を行う方が良いと思いますが、どうすればいいかわかりません。

52
user1537723

Wordの「パターン」は、非常に曖昧なため使用しないでください。常に "string"または "regexp"(またはシェルの "globbing pattern")のいずれかを使用してください。

あなたが望む具体的な答えは:

awk 'f{print;f=0} /regexp/{f=1}' file

または、正規表現の後のN番目のレコードのより一般的なソリューション(下記のイディオム "c")を専門とする:

awk 'c&&!--c; /regexp/{c=1}' file

次のイディオムは、特定の正規表現を指定して一致するレコードの範囲を選択する方法を説明しています。

a)正規表現のすべてのレコードを印刷します。

awk '/regexp/{f=1}f' file

b)正規表現の後にすべてのレコードを印刷します。

awk 'f;/regexp/{f=1}' file

c)正規表現の後、N番目のレコードを印刷します。

awk 'c&&!--c;/regexp/{c=N}' file

d)正規表現の後、N番目のレコードを除くすべてのレコードを印刷します。

awk 'c&&!--c{next}/regexp/{c=N}1' file

e)正規表現の後にN個のレコードを印刷します。

awk 'c&&c--;/regexp/{c=N}' file

f)正規表現の後、Nレコードを除くすべてのレコードを印刷します。

awk 'c&&c--{next}/regexp/{c=N}1' file

g)正規表現からN個のレコードを出力します:

awk '/regexp/{c=N}c&&c--' file

変数名を「found」の「f」から「count」の「c」に変更しました。これは、変数が実際に何であるかをより適切に表現するためです。

121
Ed Morton

あなたが興味を持っているのと一致するのは、行afterですよね? sedでは、次のように実現できます。

sed -n '/ABC/{n;p}' infile

あるいは、grepのAオプションを探しているかもしれません。

-A NUM, Print NUM lines of trailing context after matching lines.

たとえば、次の入力ファイルがある場合:

foo
bar
baz
bash
bongo

次を使用できます。

$ grep -A 1 "bar" file
bar
baz
$ sed -n '/bar/{n;p}' file
baz

お役に立てば幸いです。

37
chooban

パターンの後にすべての行を印刷する必要があったので(ok Ed、REGEX)、私はこれに決めました:

sed -n '/pattern/,$p' # prints all lines after ( and including ) the pattern

しかし、私はすべての行を印刷した後、パターンを除外したいので

sed -n '/pattern/,$p' | tail -n+2  # all lines after first occurrence of pattern

あなたの場合、最後にhead -1を追加できると思います

sed -n '/pattern/,$p' | tail -n+2 | head -1 # prints line after pattern
5
Mark

awkバージョン:

awk '/regexp/ { getline; print $0; }' filetosearch
2
tue

これはあなたのために働くかもしれません(GNU sed):

sed -n ':a;/regexp/{n;h;p;x;ba}' file

Seds grepのようなオプション-nを使用し、現在の行に必要な正規表現が含まれている場合、現在の行を次の行に置き換え、その行をホールドスペース(HS)にコピーし、行を印刷し、パターンスペースを交換します(PS) HSと繰り返します。

1
potong

パターンが一致する場合、次の行をパターンバッファにコピーし、リターンを削除してから終了します。副作用は印刷です。

sed '/pattern/ { N; s/.*\n//; q }; d'
1
Michael Back

実際、patterncontinuous行に一致する場合、sed -n '/pattern/{n;p}' filenameは失敗します。

$ seq 15 |sed -n '/1/{n;p}'
2
11
13
15

予想される答えは次のとおりです。

2
11
12
13
14
15

私の解決策は次のとおりです。

$ sed -n -r 'x;/_/{x;p;x};x;/pattern/!s/.*//;/pattern/s/.*/_/;h' filename

例えば:

$ seq 15 |sed -n -r 'x;/_/{x;p;x};x;/1/!s/.*//;/1/s/.*/_/;h'
2
11
12
13
14
15

説明:

  1. x;:入力からの各行の先頭で、xコマンドを使用して、pattern spacehold spaceの内容を交換します。
  2. /_/{x;p;x};pattern spaceであるhold spaceが実際に_を含む場合(これは、最後の行がindicatorと一致したかどうかを示すpatternにすぎません)、xを使用してcurrent lineの実際のコンテンツをpattern spaceに交換し、pを使用してcurrent lineを出力し、xを使用してこの操作を回復します。
  3. xpattern spaceおよびhold spaceの内容を復元します。
  4. /pattern/!s/.*//current linepatternと一致しない場合、つまり、次の行を印刷しないで、s/.*//コマンドを使用してpattern spaceのすべての内容を削除します。
  5. /pattern/s/.*/_/current linepatternと一致する場合、つまりNEXTの次の行を印刷する必要がある場合、indicatorを設定して、sedにNEXT行を印刷するように指示する必要があるため、s/.*/_/を使用してすべてを置換するpattern spaceの内容を_に追加します(2番目のコマンドはこれを使用して、最後の行がpatternと一致したかどうかを判断します)。
  6. hhold spacepattern spaceの内容で上書きします。次に、hold spaceのコンテンツは、^_$current linepatternに一致することを意味する、または^$current linepatternに一致しないことを意味します。
  7. s/.*/_/の後、pattern space/pattern/と一致できないため、s/.*//を実行する必要があるため、5番目のステップと6番目のステップは交換できません。
1
Weike