一致する行の後の X 行とその前の Y 行を削除します。

一致する行の後の X 行とその前の Y 行を削除します。

次の文字列があります。

core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet
none65@pci0:2:0:2:      class=0x080100 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'interface'
    class      = base peripheral
    subclass   = DMA controller
core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet

"class = Base Peripheral"の前に3行、その後に1行を削除する必要があります。たとえば、次のようになります。

core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet
core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453 
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet

私はこれを行うことができませんでした。これはFreeBSDオペレーティングシステムで行われました。

答え1

実際の使用エドまたは前任者:

ed -s file <<EOF
g/base peripheral/-3;+4d
%p
EOF
printf '%s\n' 'g/base peripheral/-3;+4d' '%p' | ex -s file

lobal はgすべての行を「デフォルト境界」としてマークし、d指定された範囲を削除します。次に%pファイルを印刷します。wを使用してファイルの変更を保存できます。

答え2

この試みawk

awk '
FNR==NR && /class[[:blank:]]*=[[:blank:]]*base peripheral/{x=NR; nextfile;}
FNR!=NR && (FNR < x-3 || FNR > x+1)
' file file

file2回食べますawk。最初はその行を探します(複数の犬がある場合は最初の行だけが一致します!)。 2番目に省略する行以外の行を印刷します。

コマンド出力とともに使用するには、次のようにします。

awk '...' <(command) <(command)

または

output="$(command)"
awk '...' <(printf '%s' "$output") <(printf '%s' "$output")

答え3

最も簡単な方法は、おそらく次のようになります。すべてのUnixシステムのすべてのシェルでawkを使用することです。

$ cat tst.awk
$0 ~ re {
    for (i=(NR-b); i<=(NR+a); i++) {
        skip[i]
    }
}
{ lines[NR] = $0 }
END {
    for (i=1; i<=NR; i++) {
        if ( !(i in skip) ) {
            print lines[i]
        }
    }
}

$ awk -v b=3 -v a=1 -v re='class[[:space:]]*=[[:space:]]*base peripheral' -f tst.awk file
    core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453 device=0xa2d2 subvendor=0x1453 subdevice=0x0008
        vendor     = 'MicSystem'
        device     = 'controller'
        class      = network
        subclass   = ethernet
    core1@pci0:2:0:1:  class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453 device=0xa2d2 subvendor=0x1453 subdevice=0x0008
            vendor     = 'MicSystem'
            device     = 'controller'
            class      = network
            subclass   = ethernet

入力がシェルに保存されておらず、パイプから出力される場合は、whatever | awk -v ... -f tst.awk入力をスクリプトに渡すすべてのタスクを実行または実行します。

上記の解決策と同様に、ed入力全体がメモリに読み込まれますが、入力長が数億行でない場合は問題ありません。これが実際にそうであれば、b現在の行が正規表現と一致しないときに常に配列の最初の要素を印刷するようにサイズ配列であるスクロールバッファを実装できます。しかし、この場合、書くにはもっと考えが必要で、書くのが難しくなります。重なり合う範囲を処理します。

答え4

問題は、この行の前後にあまりにも多くの行を削除することで説明されていますが、これらの意図された編集の効果は、「プロパティがその値を持つアイテムを削除する」とclassいうbase peripheralより高いレベルの意味を持つことは明らかです。

より大きな文書の構造に関連するこのタイプの変換操作に非常に適した言語がある。TxR

他の人が理解しやすいコードを使用してフィールド抽出を詳細に実行したり、17ヶ月後にあなたが理解できるようにすることができます。

@(repeat)
@addr: class=0x@cl rev=0x@rev hdr=0x@hdr vendor=0x@ven
    vendor     = '@vendor'
    device     = '@device'
    class      = @class
    subclass   = @subclass
@  (require (nequal class "base peripheral"))
@  (output)
@addr: class=0x@cl rev=0x@rev hdr=0x@hdr vendor=0x@ven
    vendor     = '@vendor'
    device     = '@device'
    class      = @class
    subclass   = @subclass
@  (end)
@(end)

ランニング:

$ txr data.txr data
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet
core1@pci0:2:0:1: class=0x020000 rev=0x00 hdr=0x00 vendor=0x1453
    vendor     = 'MicSystem'
    device     = 'controller'
    class      = network
    subclass   = ethernet

ここで、パターンマッチングアサーションは@(require expr)falseの場合、不要なエントリを削除しますexpr

フィルタリングを任意に複雑にし、必要に応じて出力形式を簡単に変更できます。内蔵のTXR Lisp言語には魔法のような超能力もあります。

関連情報