sedの「ホールドスペース」と「パターンスペース」の概念


86

sedの2つの概念であるホールドスペースとパターンスペースに混乱しています。誰かがそれらを説明するのを手伝ってもらえますか?

マニュアルの抜粋は次のとおりです。

h H    Copy/append pattern space to hold space.
g G    Copy/append hold space to pattern space.

n N    Read/append the next line of input into the pattern space.

これらの6つのコマンドは本当に私を混乱させます。


4
自分で試してみてください:echo $'1\n2\n3\n4' | sed -n '1~2h;2~2{p;x;p}'
choroba 2012年

4
混同しないでください。使用しないでください。1行の単純な置換以外の場合は、sedではなくawkを使用する必要があります。ホールドスペース、パターンスペース、およびsed言語構造の95%は、より良い代替手段がないawkの前に発明されました。それらは、awkが1970年代半ばに発明されるとすぐに時代遅れになり、awkで単純かつ慎重に行うのではなく、sedsの難解な構文を使用して問題を解決することを楽しむ人々によってのみ今日生き続けています。sedでs、g、p(-nを含む)を超えて使用している場合は、ほぼ間違いなく間違ったツールを使用しています。
エド・モートン

26
Morton awkは構造化データを処理します(各行は同じ構造を持っています)。Sedは、生のランダムデータを処理することを目的としています。したがって、sedの代わりに単にawkを使用することはできません。
ピチコス2014年

5
読むことを強くお勧めしますinfo sed。ベアマンページよりもはるかに詳細です。
フェルナンドバッソ2016年

4
私はピティコスに同意します。私はモートンと同じように車線を下り、モートンと同じ質問をしました。しかし、私はまだそれを簡単に却下することはできませんでした。
eigenfield 2017年

回答:


111

sedがファイルを1行ずつ読み取ると、現在読み取られている行がパターンバッファー(パターンスペース)に挿入されます。パターンバッファは、現在の情報が保存されるスクラッチパッドである一時バッファのようなものです。sedに印刷するように指示すると、パターンバッファが印刷されます。

ホールドバッファ/ホールドスペースは長期保存のようなもので、何かをキャッチして保存し、後でsedが別の行を処理しているときに再利用できます。ホールドスペースを直接処理するのではなく、何かをしたい場合は、ホールドスペースをコピーするか、パターンスペースに追加する必要があります。たとえば、printコマンドpは、パターンスペースのみを印刷します。同様sに、パターン空間で動作します。

次に例を示します。

sed -n '1!G;h;$p'

(-nオプションは、行の自動印刷を抑制します)

そこ三つのコマンドはここにある:1!Gh$p1!G住所、持っている1(最初の行)が、!コマンドはどこにでも実行されることを意味しますが、最初の行にします。$p一方、最後の行でのみ実行されます。だから何が起こるかこれは:

  1. 最初の行が読み取られ、パターンスペースに自動的に挿入されます
  2. 最初の行では、最初のコマンドは実行されません。h最初の行を保留スペースにコピーします。
  3. これで、2行目がパターンスペースにあったものを置き換えます
  4. 2行目では、最初にを実行しG、ホールドバッファの内容をパターンバッファに追加し、改行で区切ります。パターンスペースには、2行目、改行、および1行目が含まれています。
  5. 次に、hコマンドはパターンバッファの連結された内容をホールドスペースに挿入します。ホールドスペースは、反転した2行目と1行目を保持します。
  6. 3行目に進みます-上記のポイント(3)に進みます。

最後に、最後の行が読み取られ、ホールドスペース(前のすべての行が逆の順序で含まれている)がパターンスペースに追加された後、パターンスペースはp。で出力されます。ご想像のとおり、上記はtacコマンドが実行することを正確に実行します-ファイルを逆に出力します。


3
Gとhのオプションは「切り取りと追加」のように機能しますか?「コピーして追加」操作のようには見えません。
スマイル

ネストされたコマンド(中括弧)を使用すると、パターンとホールドスペースが追加されますか?'195,210{/add/p}'…パターンに含まれる行のグループの最後の行を抽出することは可能ですか?
サンドバーグ2018

17

@エドモートン:私はここであなたに同意しません。sed複数行のgrepを実行するためのエレガントな方法を考え出すには、非常に便利で簡単であることがわかりました(パターンの概念を理解し、バッファーを保持すると)。

たとえば、ホスト名と各ホストに関する情報が含まれているテキストファイルを見てみましょう。その間に、私が気にしない多くのがらくたがあります。

Host: foo1
some junk, doesnt matter
some junk, doesnt matter
Info: about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Info: a second line about foo1 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter
Host: foo2
some junk, doesnt matter
Info: about foo2 that I really care about!!
some junk, doesnt matter
some junk, doesnt matter

私にとって、ホスト名と対応するinfo行を含む行を取得するawkスクリプトは、sedで実行できるよりも少し時間がかかります。

sed -n '/Host:/{h}; /Info/{x;p;x;p;}' myfile.txt

出力は次のようになります。

Host: foo1
Info: about foo1 that I really care about!!
Host: foo1
Info: a second line about foo1 that I really care about!!
Host: foo2
Info: about foo2 that I really care about!!

Host: foo1出力に2回表示されることに注意してください。)

説明:

  1. -n 明示的に印刷されない限り、出力を無効にします
  2. 最初の一致、Host:行を見つけてホールドバッファに入れます(h)
  3. 2番目の一致は、次のInfo:行を検索しますが、最初にパターンバッファー内の現在の行をホールドバッファーとHost:交換(x)し、その行を出力(p)してから、再交換(x)してInfo:行を出力(p)します。

はい、これは単純な例ですが、これは単純なsedワンライナーですぐに対処された一般的な問題だと思います。特定の予測可能なシーケンスに依存できないタスクなど、はるかに複雑なタスクの場合は、awkの方が適している場合があります。


2
この場合、grepを使用することもできますが、grep 'Host\|Info'
Pithikos 2014年

特定のホストの後に2つの情報行がある場合、@ JensJensonは、両方の情報行の前に情報行を配置する必要があります。それに応じて答えを編集すると思います。Pithikos、grepでは十分ではありません。
アーロンマクデイド2014年

3
@ JensJenson、awksedコードに相当するものもかなり短いです:awk '/Host:/{hold=$0}; /Info/{print hold; print;}' myfile.txt
Aaron McDaid

11

@Januaryの答えと例は素晴らしいですが、説明は私には十分ではありませんでした。正確にどのようにsed -n '1!G;h;$p'機能するかを理解するまで、私は多くのことを検索して学ぶ必要がありました。それで、私のような誰かのためのコマンドについて詳しく説明したいと思います。

まず、コマンドの機能を見てみましょう。

$ echo {a..d} | tr ' ' '\n' # Prints from 'a' to 'd' in each line
a
b
c
d
$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;$p'
d
c
b
a

tacコマンドと同じように入力を逆にします。

sed行ごとに読み取るので、各行のパッテンスペースホールドスペースで何が起こるかを見てみましょう。通りhのコマンドをコピーホールドスペースにパターンスペースの内容、両空間は同じテキストを持っています。

Read line    Pattern Space / Hold Space    Command executed
-----------------------------------------------------------
a            a$                            h
b            b\na$                         1!G;h
c            c\nb\na$                      1!G;h
d            d\nc\nb\na$                   1!G;h;$p

最後の行で、次のようにフォーマットされた$p印刷d\nc\nb\na$

d
c
b
a

各行のパターンスペースを確認したい場合は、lコマンドを追加できます。

$ echo {a..d} | tr ' ' '\n' | sed -n '1!G;h;l;$p'
a$
b\na$
c\nb\na$
d\nc\nb\na$
d
c
b
a

このビデオチュートリアルを見ると、sedがどのように機能するかを理解するのに非常に役立ちます。男は、各スペースがどのように使用されるかを段階的に示しています。ホールドスペースは第4チュートリアルで参照されていますが、に慣れていない場合はすべてのビデオを視聴することをお勧めしsedます。

また、GNUsedドキュメントBruceBarnettのSedチュートリアルは非常に優れたリファレンスです。


2
何かを追加しない限り、すべての実用的な目的のための保留スペースが空であることに言及することも役立つと思います。
2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.